VP记录:Codeforces Round 856 (Div. 2) A~D
创始人
2024-06-02 14:16:10

传送门:CF

A题 Prefix and Suffix Array:

这道题的关键在于通过所有的字符前缀和后缀来找到题目所给出的字符串是是什么.当我们的出了字符串之后,判断回文就十分简单了
对于所有前后缀,我们会发现只要找到两个长度为n−1n-1n−1的字符即可,因为对于长度为n−1n-1n−1的字符只有两个并且只要我们合并这两个字符就得出了原本的字符串

下面是具体的代码部分:

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {ll x=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int main() {int T=read();while(T--) {int n=read();string s;string s1="",s2="";int cnt=1;while(cnt<=2*n-2) {cin>>s;if(s.length()==n-1) {if(s1=="") {s1=s;}else{s2=s;}}cnt++;}string lasts="";if(s1.substr(1,n-2)==s2.substr(0,n-2)) {lasts=s1+s2.substr(n-2,1);}else {lasts=s2+s1.substr(n-2,1);}string last2=lasts;reverse(last2.begin(),last2.end());if(last2==lasts) cout<<"Yes"<

B题 Not Dividing

对于本题我是简单的猜想了一个解决方法,从前往后进行遍历,如果后面的数字能被前一个数字整除,那么我们将后面的数字+1,这样就解决了整除问题了.当然对于前一个位置是1的时候,我们就应该改变1的值,将1改为2,然后假设当前的数字能被2整除就将当前的数字+1即可

除了上述,代码中还存在一些细节问题,具体请参考代码

我们发现对于每一个数字我们都只改变一次即可搞定整除问题,所以该解决方法满足题意

下面是具体的代码部分:

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {ll x=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int T;int a[maxn];int ans[maxn];
int main() {T=read();while(T--) {int n=read();for(int i=1;i<=n;i++) {a[i]=read();}for(int i=1;i<=n;i++) {if(i==1) {if(a[i]==1) {a[i]+=1;}ans[i]=a[i];continue;}if(a[i]%a[i-1]==0) {a[i]++;}else {if(a[i]==1) {if(a[i-1]==2) {a[i]=3;}else {a[i]=2;}}}ans[i]=a[i];}for(int i=1;i<=n;i++) printf("%d ",ans[i]);printf("\n");}return 0;
}

C题 C. Scoring Subsequences

本题需要一些思维进行解决,符合CF的C题思维题的想法

对于一串序列,我们需要找到满足题意的最大的最长子序列.我们先想一下如何满足最大.题目中给了大小不下降的这一个条件,显然就应该从这里来着手.我们发现分母部分是d!d!d! d\quad dd是我们的长度.我们想最大,贪心的去想一下,对于任意的长度kkk来说,我们的分母的大小是确定的,所以我们想保证最大就需要分子最大,那么我们应该从大往小进行选取字母.

到此这道题的解法就呼之欲出了.对于一段序列,我们从后往前进行枚举,然后我们的长度不断增加,也就是分母的权重每一次都增加一个当前长度的贡献,那么显然的,如果当前我们分子上增加的a[i]a[i]a[i]如果比不上分母增加的贡献的话,此时我们肯定是在减少的.所以我们现在的目标就是判断当前长度的端点和长度的关系就可.我们可以使用二分来解决,二分长度.然后再判断一下a[i−(mid−1)]a[i-(mid-1)]a[i−(mid−1)]是不是满足即可

下面是具体的代码部分:

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {ll x=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int T;int a[maxn];
vectorv;
int main() {T=read();while(T--) {int n=read();v.clear();for(int i=1;i<=n;i++) a[i]=read();printf("1 ");v.push_back(1);for(int i=2;i<=n;i++) {int l=1,r=i;int ans=1;while(l<=r) {int mid=(l+r)>>1;if(a[i-(mid-1)]>=mid) {l=mid+1;ans=mid;}else {r=mid-1;}}printf("%d ",ans);}printf("\n");}return 0;
}

D题 Counting Factorizations

一道组合数的题目.

对于给定的所有序列来说,显然只有质数是可以作为底数的,所以我们需要找出所有的质数,然后对于每一种质数来说,我们可能有多个,但是因为质因数分解的性质我们只能使用一个.

为了方便起见,我们预处理出每一个数的个数.对于每一个质数的个数我们使用cicici来表示,对于不是质数的个数我们使用bibibi来表示.

我们假设选出了n个质数来作为底数(当然,当我们的质数的个数不及n个的时候是无解的,此时假设有解).因为我们挑出了质数,所以此时我们用dididi来表示剩下来质数的个数,那么此时我们的总个数应该就是
n!(b1!∗b2!∗b3!∗...∗bk1!)∗(d1!∗d2!∗...∗dk2!)\frac{n!}{(b1!*b2!*b3!*...*bk1!)*(d1!*d2!*...*dk2!)} (b1!∗b2!∗b3!∗...∗bk1!)∗(d1!∗d2!∗...∗dk2!)n!​
我们发现对于n!b1!∗b2!∗b3!∗...∗bk1!\frac{n!}{b1!*b2!*b3!*...*bk1!}b1!∗b2!∗b3!∗...∗bk1!n!​是一个定值,我们可以直接计算出来
所以此时我们的问题就是如何计算出每一种选取方法的∏di\prod\limits{d_i}∏di​值即可

对于这个问题我们可以使用dpdpdp来进行解决.我们使用dp[i][j]dp[i][j]dp[i][j]来表示前iii个质数选取jjj个质数的每一种情况的∏1idk\prod\limits_{1}^{i}{d_k}1∏i​dk​的总和(这里很多题解都讲的不是很清楚),
那么对于第iii位来说,我们可以选择选取第iii个质数,此时我们的dk=ck−1dk=ck-1dk=ck−1,此时我们会发现此时我们可以由前一位进行递推,因为对于前i−1i-1i−1个质数选择j−1j-1j−1的每一种情况,都可以通过选择当前质数来达到jjj的情况,所以当前的总和就等于之前的总和乘上dkdkdk
假设不选取,dk=ckdk=ckdk=ck,那么当前总和就等于之前的总和乘上dkdkdk

所以dp[i][j]=dp[i−1][j−1]∗(ck−1)+dp[i−1][j]∗(ck)dp[i][j]=dp[i-1][j-1]*(ck-1)+dp[i-1][j]*(ck)dp[i][j]=dp[i−1][j−1]∗(ck−1)+dp[i−1][j]∗(ck)

本题需要使用逆元,具体参考代码

下面是具体的代码部分:

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {ll x=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*w;
}
#define int long long
#define maxn 1000010
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
const int mod=998244353;
int n;int a[maxn];int fac[maxn],infac[maxn];
int check(int x) {if(x==1) return false;for(int i=2;i<=__builtin_sqrt(x);i++) {if(x%i==0) return false; }return true;
}
setprime;setin_prime;
mapmp;int dp[4400][4400];
int qpow(int x,int y) {int ans=1;while(y) {if(y&1) ans=(ans*x)%mod;y>>=1;x=(x*x)%mod;}return ans;
}
signed main() {n=read();for(int i=1;i<=2*n;i++) {a[i]=read();if(check(a[i])) prime.insert(a[i]);else in_prime.insert(a[i]);mp[a[i]]++;}fac[0]=1;infac[0]=1;for(int i=1;i<=1e6+1;i++) {fac[i]=fac[i-1]*i%mod;infac[i]=infac[i-1]*qpow(i,mod-2)%mod;}int ans=fac[n];for(auto i : in_prime) {ans=(ans*infac[mp[i]])%mod;}int cnt=0;dp[0][0]=1;for(auto i : prime) {cnt++;dp[cnt][0]=dp[cnt-1][0]*infac[mp[i]]%mod;for(int j=1;j<=min(cnt,n);j++) {dp[cnt][j]=(dp[cnt-1][j-1]*infac[mp[i]-1]%mod+dp[cnt-1][j]*infac[mp[i]]%mod)%mod;}}ans=(ans*dp[cnt][n])%mod;cout<

相关内容

热门资讯

苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...