CF17 合集

前言:

  1. 本人不会 LaTeX……请见谅
  2. 码风奇特,不喜勿喷哈
  3. 题面翻译取自 luogu,本蒟蒻也会安置原题链接
  4. 保证文章中不出现“显然”或者“注意到”,可能会出现“易证”
  5. AC 代码会放置在每一个题目的最底端,为防止 ban 码的情况出现,不设置跳转链接
  6. 有写错的地方欢迎各位神犇指正
  7. 本套题共 \(5\) 道,预计阅读 + 理解时间小于 \(40\) min

正片开始!

CF17A

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

签到题,直接做做完了

推理过程:

线性筛

直接枚举模拟即可

细节处理:

比对的过程不要下标越界捏!

代码:

点击查看代码
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1024;
int n,k,prime[maxn],cnt;
bool isprime[maxn];
inline void euler(){
    memset(isprime,true,sizeof(isprime));
    isprime[1]=false;
    for(int i=2;i<=n;i++){
        if(isprime[i]){
        	prime[++cnt]=i;
		}
        for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
            isprime[i*prime[j]]=false;
			if(i%prime[j]==0){
				break;
			}
        }
    }
    return;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>k;
	euler();
	int tot=0;
	for(int i=3;i<=cnt;i++){
		for(int j=2;j<i;j++){
			if(prime[j-1]+prime[j]+1==prime[i]){
				tot++;
			}
		} 
	}
	if(tot>=k){
		cout<<"YES"<<endl;
	}else{
		cout<<"NO"<<endl;
	}
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF17B

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

签到题 $ \times 2 $

推理过程:

这不直接最小生成树板子吗?

云落刚好昨天写了高效进阶最小生成树的题解呢!

细节处理:

代码:

点击查看代码
#include<iostream>
#include<algorithm>
const int maxn=1024,maxm=1e4+10;
using namespace std;
int n,m,a[maxn];
bool fa[maxn];
struct node{
	int u,v,w;
	friend bool operator < (const node &x,const node &y){
		return x.w<y.w;
	}
}e[maxm];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>e[i].u>>e[i].v>>e[i].w;
	}
	sort(e+1,e+m+1);
	int ans=0,cnt=0;
	for(int i=1;i<=m;i++){
		int x=e[i].u,y=e[i].v,z=e[i].w;
		if(!fa[y]&&a[x]>a[y]){
			fa[y]=true;
			ans+=z;
			cnt++;
		}
		if(cnt==n-1){
			break;
		}
	}
    if(cnt==n-1){
    	cout<<ans<<endl;
    }else{
    	cout<<-1<<endl;
	}
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF17C

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:紫题(建议降绿)

推理过程:

虚假的字符串,真实的 dp

钦定 $ f_{i,x,y,z} $ 表示前 $ i $ 个字符中有 $ x $ 个“a”,$ y $ 个“b”,$ z $ 个“c”

有转移方程:

\[ f_{i,x,y,z} \rightarrow \left\{ \begin{aligned} f_{nxt_{i,0},x,y,z} \\ f_{nxt_{i,1},x,y,z} \\ f_{nxt_{i,2},x,y,z} \\ \end{aligned} \right. \]

其中 $ nxt_{i,0/1/2} $ 表示位置 $ i $ 上 $ a,b,c $ 下一个可拓展位置

细节处理:

这题卡空间

$ maxn=150+10 $ 会喜提 MLE

$ maxn=150+1 $ 会喜提 RE

二分答案得到 $ maxn=150+5 $,可以 AC 力!

代码:

点击查看代码
#include<iostream>
using namespace std;
const int maxn=155,maxl=55,mod=51123987;
int n;
string s;
int nxt[maxn][3],dp[maxn][maxl][maxl][maxl];
int main(){
    ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
    cin>>n>>s;
    s=' '+s;
    nxt[n+1][0]=n+1;
	nxt[n+1][1]=n+1;
	nxt[n+1][2]=n+1;
    for(int i=n;i>=1;i--){
        nxt[i][0]=nxt[i+1][0];
        nxt[i][1]=nxt[i+1][1];
        nxt[i][2]=nxt[i+1][2];
        nxt[i][s[i]-'a']=i;
    }
    dp[1][0][0][0]=1;
	int ans=0;
    for(int i=1;i<=n;i++){
        for(int x=0;x<=(n+2)/3;x++){
            for(int y=0;y<=(n+2)/3;y++){
                for(int z=0;z<=(n+2)/3;z++){
                    if(x+y+z==n&&abs(x-y)<=1&&abs(x-z)<=1&&abs(y-z)<=1){
                    	ans=(ans+dp[i][x][y][z])%mod;
                    }
                    dp[nxt[i][0]][x+1][y][z]=(dp[nxt[i][0]][x+1][y][z]+dp[i][x][y][z])%mod;
                    dp[nxt[i][1]][x][y+1][z]=(dp[nxt[i][1]][x][y+1][z]+dp[i][x][y][z])%mod;                    
                    dp[nxt[i][2]][x][y][z+1]=(dp[nxt[i][2]][x][y][z+1]+dp[i][x][y][z])%mod;
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF17D

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:紫题?(扩展欧拉定理直接秒……)

推理过程:

形式化题意,求 $ x $ 的值,满足 $ (a-1) \times a^{n-1} \equiv x \bmod c $

注意到恐怖的数据范围,直接扩展欧拉定理安排上

有 $ a^{n-1} \equiv a^{(n-1) \bmod \phi (c) + \phi (c) } \bmod c $

然后就直接快速幂即可!

细节处理:

代码:

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long
using namespace std;
const int maxn=1e6+10;
char sb[maxn],sn[maxn];
int c;
bool flag;
inline int qpow(int a,int b){
	int res=1;
	while(b){
		if(b&1){
			res=res*a%c;
		}
		a=a*a%c;
		b>>=1;
	}
	return res;
}
signed main(){
	scanf("%s%s%lld",sb+1,sn+1,&c);
	int tmp=c,phi=c;
	int len1=strlen(sb+1),len2=strlen(sn+1);
	for(int i=2;i*i<=tmp;i++){
		if(tmp%i==0){
			phi=phi/i*(i-1);
			while(tmp%i==0){
				tmp/=i;
			}
		}
	}
	if(tmp>1){
		phi=phi/tmp*(tmp-1);
	}
	int b=0;
	for(int i=1;i<=len1;i++){
		b=(b*10+sb[i]-'0')%c;
	}
	for(int i=len2;i>=1;i--){
		if(sn[i]=='0'){
			sn[i]='9';
		}else{
			sn[i]--;
			break;
		}
	}
	int n=0;
	bool flag=false;
	for(int i=1;i<=len2;i++){
		n=n*10+sn[i]-'0';
		if(n>=phi){
			flag=true;
		}
		n%=phi;
	}
	if(flag){
		n+=phi;
	}
	int ans=((b-1)*qpow(b,n)%c+c)%c;
	if(ans==0){
		printf("%lld\n",c);
	}else{
		printf("%lld\n",ans);
	}
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF17E

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:紫题(Manacher 模板变式?)

推理过程:

回文串直接 Manacher

钦定 $ f_i,g_i $ 分别表示以 $ i $ 为开头的回文串有多少个,以 $ i $ 为结尾的回文串有多少个

显然有 $ ans=\sum _{i=1} ^{n} f_i \sum _{j=1} ^{i-1} g_i $

前缀和维护 $ g_i $,差分维护 $ f_i $

细节处理:

关于云落马拉车数组没双倍空间虚空调试两个点这件事

代码:

点击查看代码
#pragma GCC optimize("Ofast,unroll-loops")
#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long
using namespace std;
const int maxn=2e6+10,mod=51123987;
int n;
char a[maxn<<1],s[maxn<<1];
int r[maxn<<1],f[maxn<<1],g[maxn<<1],tot;
inline void init(){
    s[0]='^';
    s[n<<1|1]='%';
    for(int i=1;i<=n;i++){
    	s[(i<<1)-1]='%';
		s[i<<1]=a[i];
	}
    return;
}
inline void manacher(){
	int p=0,mx=0;
    for(int i=1;i<=(n<<1|1);i++){
    	if(i<mx){
    		r[i]=min(mx-i,r[(p<<1)-i]);
		}else{
			r[i]=1;
		}
        while(i-r[i]>=1&&i+r[i]<=(n<<1|1)&&s[i-r[i]]==s[i+r[i]]){
        	r[i]++;
		}
        if(i+r[i]>mx){
        	mx=i+r[i];
			p=i;
		}
        tot=(tot+(r[i]>>1))%mod;
    }
    return;
}
signed main(){
    scanf("%lld%s",&n,a+1);
    init();
    manacher();
    for(int i=1;i<=((n<<1)|1);i++){
    	f[i-r[i]+1]++;
		f[i+1]--;
		g[i]++;
		g[i+r[i]]--;
	}
    for(int i=1;i<=((n<<1)|1);i++){
    	f[i]+=f[i-1];
		g[i]+=g[i-1];
	}
    int sum=0,ans=(tot-1)*tot/2%mod;
    for(int i=2;i<=((n<<1)|1)-2;i+=2){
        sum=(sum+g[i])%mod;
        ans=(ans-sum*f[i+2]%mod+mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

完结撒花!

posted @ 2024-11-24 13:28  sunxuhetai  阅读(31)  评论(0)    收藏  举报