winter week5 day3
2024牛客寒假算法基础集训营5
A
思路:1既不是质数也不是合数
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { int n; cin>>n; int m=n; for(int i=0;i<n;++i){ int x; cin>>x; if(x==1)m--; } cout<<m; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; while(t--){ solve(); } return 0; }
B
思路1:由于不能删连续的两个字符,则一个mygo带来的贡献在原串中的形式有8种(在mygo中任意插空格),其余位置可以任意删,枚举所有形式的贡献即可。f[i]表示一段长度为i且可以任意操作的串的删除总数,可以推出f[i]=f[i-1]+f[i-2],分别为不删第i个和删第i个
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; string s[8]={"mygo","m ygo","my go","myg o","m y go","m yg o","my g o","m y g o"}; void solve() { string x; cin>>x; int n,ans=0; n=x.size(); vector<int>f(n+1); f[0]=1,f[1]=2; for(int i=2;i<=n;++i)f[i]=(f[i-1]+f[i-2])%mod; auto check=[](string a,string b){ for(int i=0;i<b.size();++i){ if(b[i]==' ')continue; if(a[i]!=b[i])return false; } return true; }; for(int i=0;i<n;++i){ for(int j=0;j<8;++j){ if(i+s[j].size()-1>=n)continue; string u=x.substr(i,s[j].size()); if(check(u,s[j]))ans=(ans+f[i]*f[n-i-s[j].size()]%mod)%mod; } } cout<<ans; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; // init(); while(t--){ solve(); } return 0; }
思路2:f[i][j]表示前i个里第i个选(不删)或不选(删)的mygo的方案数
不选:f[i][0]=f[i-1][1]
选:f[i][1]=f[i-1][1]+f[i-1][0]+s[i]=='o'时前i-1里前缀为myg的方案数
对于前i-1里前缀为myg的方案数可由前缀为my表示,依次类推,更新前缀为任意值、m、my、myg的方案数
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; string s[8]={"mygo","m ygo","my go","myg o","m y go","m yg o","my g o","m y g o"}; int f[N][2][4]; void solve() { string x; cin>>x; int n=x.size(); x.insert(x.begin(),' '); if(x[1]=='m'){ f[1][1][1]=f[1][0][0]=1; }else{ f[1][1][0]=f[1][0][0]=1; } for(int i=2;i<=n;++i){ f[i][0][0]=f[i-1][1][0]; f[i][0][1]=f[i-1][1][1]; f[i][0][2]=f[i-1][1][2]; f[i][0][3]=f[i-1][1][3]; f[i][1][0]=(f[i-1][1][0]*(x[i]!='m')+f[i-1][1][1]*(x[i]!='m'&&x[i]!='y')+f[i-1][1][2]*(x[i]!='m'&&x[i]!='g')+f[i-1][1][3]*(x[i]!='m') + f[i-1][0][0]*(x[i]!='m')+f[i-1][0][1]*(x[i]!='m'&&x[i]!='y')+f[i-1][0][2]*(x[i]!='m'&&x[i]!='g')+f[i-1][0][3]*(x[i]!='m'))%mod; f[i][1][1]=((x[i]=='m')*(f[i-1][1][0]+f[i-1][1][1]+f[i-1][1][2]+f[i-1][1][3]+f[i-1][0][0]+f[i-1][0][1]+f[i-1][0][2]+f[i-1][0][3]))%mod; f[i][1][2]=(f[i-1][1][1]+f[i-1][0][1])*(x[i]=='y')%mod; f[i][1][3]=(f[i-1][1][2]+f[i-1][0][2])*(x[i]=='g')%mod; } vector<array<int,2>>g(n+1); for(int i=1;i<=n;++i){ g[i][0]=g[i-1][1]; g[i][1]=(g[i-1][0]+g[i-1][1]+(x[i]=='o')*(f[i-1][1][3]+f[i-1][0][3]))%mod; } cout<<(g[n][0]+g[n][1])%mod; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; // init(); while(t--){ solve(); } return 0; }
C
思路:模拟
对于一个大于1的数x,x减去1则可以在x旁添加1个0,最多添加x-1个,这样x和这些0这一段数的平均值为1;由于添加的0也会影响到原本x旁边的数y,那就取min(x-1,y-1),让x和y都同时减,统计总共减的个数
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { int n; cin>>n; vector<int>a(n); for(int i=0;i<n;++i)cin>>a[i]; int ans=0; ans+=a[0]-1; for(int i=1;i<n-1;++i){ int c=min(a[i],a[i+1])-1; ans+=c; a[i]-=c,a[i+1]-=c; } if(n!=1) ans+=a[n-1]-1; cout<<ans; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; while(t--){ solve(); } return 0; }
E
思路:首先偶数肯定是可以的,每次相邻数的差加一,可以操作无限次。其次是奇数,最后一个数是变不了的,那就是看能否让操作次数尽可能少,且倒数第二个数要不大于最后一个数。这里可以考虑倒着处理,由于最后一个数不能变,那就可以由它与前一个数的差值求出前一个数最多能操作多少次,往前同理。最后看序列是否非递减即可
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { int n; cin>>n; vector<int>ve(n+1),cnt(n+1); for(int i=1;i<=n;++i){ cin>>ve[i]; } if(n%2==0||n==1)cout<<"YES\n"; else{ int k=0; for(int i=n-1;i>=1;--i){ if(i%2==0){ int now=ve[i]+k*i; if(now>ve[i+1]){ cout<<"NO\n"; return ; } k+=(ve[i+1]-now)/i; } ve[i]+=k*i; if(ve[i]>ve[i+1]){ cout<<"NO\n"; return ; } } cout<<"YES\n"; } } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; cin>>t; // init(); while(t--){ solve(); } return 0; }
F
soyorin的数组操作(hard)
这道题很容易被easy影响到。最初想esay的做法时其实就是hard的答案😅,就是最大相邻差值,但是easy写错了好几个思路,写hard的时候就没往那方面想,但是这道还是得会easy才能出hardqwq。
思路:先和easy一样判断是否可以。然后就是求最少次数,一个数的操作次数即为它与前一个数的差值,每个数如此,并且可以覆盖其前面的数的操作,假如前面有个数操作一次,当前这个数也要一次,就可以由当前这个数的操作覆盖前面那个数的操作,实际上总共只需要一次。那其实就是求最大相邻差值
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { int n,ans=0; cin>>n; vector<int>ve(n+1),cnt(n+1); for(int i=1;i<=n;++i){ cin>>ve[i]; if(i>1)ans=max(ans,ve[i-1]-ve[i]); } if(n%2==0||n==1) { } else{ int k=0; for(int i=n-1;i>=1;--i){ if(i%2==0){ int now=ve[i]+k*i; if(now>ve[i+1]){ cout<<"-1\n"; return ; } k+=(ve[i+1]-now)/i; } ve[i]+=k*i; if(ve[i]>ve[i+1]){ cout<<"-1\n"; return ; } } } cout<<ans<<'\n'; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; cin>>t; // init(); while(t--){ solve(); } return 0; }
G
同hard
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; int st[2*N]; int primes[2*N],cnt; void init(){ for(int i=2;i<=2*N;++i){ if(!st[i])primes[cnt++]=i; for(int j=0; primes[j]*i<=2*N;++j){ st[primes[j]*i]=true; if(i%primes[j]==0)break; } } } void solve() { int n; cin>>n; vector<int>ans(n+1); for(int i=n,r=n;i>0;--i){ if(!st[i+r]){ for(int j=i,p=r;j<=r;++j)ans[j]=p--; r=i-1; } } for(int i=1;i<=n;++i)cout<<ans[i]<<' '; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; init(); while(t--){ solve(); } return 0; }
H
思路:如果x+y为质数(x<y),在位置{x,x+1,...,y-1,y}可以构造出{y,y-1,...,x+1,x},使得每个数的值为x+y
先预处理出2n以内的质数,从n往前一段一段的找x、y
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; int st[2*N]; int primes[2*N],cnt; void init(){ for(int i=2;i<=2*N;++i){ if(!st[i])primes[cnt++]=i; for(int j=0; primes[j]*i<=2*N;++j){ st[primes[j]*i]=true; if(i%primes[j]==0)break; } } } void solve() { int n; cin>>n; vector<int>ans(n+1); for(int i=n,r=n;i>0;--i){ if(!st[i+r]){ for(int j=i,p=r;j<=r;++j)ans[j]=p--; r=i-1; } } for(int i=1;i<=n;++i)cout<<ans[i]<<' '; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; init(); while(t--){ solve(); } return 0; }
I
思路:分类讨论
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { int t,a,k; cin>>t>>a>>k; int ans; if(t*a>=0){ t=abs(t),a=abs(a); if(a<=t)ans=t; else{ ans=2*a-t; } }else{ t=abs(t),a=abs(a); if(a<=k)ans=2*a+t; else ans=3*t+2*a; } cout<<ans; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; while(t--){ solve(); } return 0; }
J
思路:贪心+dp
当相邻两个数相同时差最小,那就让相同的数尽可能多。若相邻两个数的区间相交说明可以取相同的数,可以取两个区间的交集,那就遍历所有区间,将可以合并的区间合并,统计所有合并后的区间。统计后的区间相邻都是没有交集的,也就是选出来的相邻数一定会有差值。一个区间中选最大和最小是最优的,那就用dp求就好了
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { int n; cin>>n; vector<PII>ve(n),g; for(int i=0;i<n;++i){ cin>>ve[i].first>>ve[i].second; } int l=ve[0].first,r=ve[0].second; for(int i=1;i<n;++i){ if(ve[i].second>=l&&ve[i].first<=r){ l=max(l,ve[i].first),r=min(r,ve[i].second); }else{ g.push_back({l,r}); l=ve[i].first,r=ve[i].second; } } g.push_back({l,r}); vector<array<int,2>>f(g.size()); for(int i=1;i<g.size();++i){ f[i][0]=min(f[i-1][0]+abs(g[i].first-g[i-1].first),f[i-1][1]+abs(g[i].first-g[i-1].second)); f[i][1]=min(f[i-1][0]+abs(g[i].second-g[i-1].first),f[i-1][1]+abs(g[i].second-g[i-1].second)); } cout<<min(f[g.size()-1][0],f[g.size()-1][1]); } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; // init(); while(t--){ solve(); } return 0; }
K
思路:其实是完全背包,没有限制被传播的是谁,每个人的花费以及传播人数都知道,并且可以多次传播,就是求完全背包,然后至少要有一个人是花费p的
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { int n,p; cin>>n>>p; vector<int>dp(n+1,INF); dp[0]=0; for(int i=1;i<=n;++i){ int a,b; cin>>a>>b; if(b>=n)b=n-1; for(int j=0;j<=n;++j) dp[j]=min(dp[j],dp[max(0ll,j-b)]+a); } int ans=INF; for(int i=0;i<n;++i){ ans=min(ans,dp[i]+(n-i)*p); } cout<<ans; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; // init(); while(t--){ solve(); } return 0; }
L
思路:推式子
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { //a+b=n //a-b=x //a=(n+x)/2; //b=n-a; //b=(n-x)/2; int n,x; cin>>n>>x; if((n+x)%2||(n-x)%2){ cout<<-1; }else{ int a=(n+x)/2,b=n-a; cout<<a<<' '<<b; } } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; // cin>>t; while(t--){ solve(); } return 0; }
M
思路:分成至少两个连通块其实就是形成下面三种情况,如果存在下面位置的相同数字则答案为1,否则答案为2,可以通过两种数形成下面情况
❌ | ❌ | ❌ | ||||||
❌ | ❌ | ❌ |
查看代码
#include<bits/stdc++.h> using namespace std; #define int long long //#define int __int128 #define double long double typedef pair<int,int>PII; typedef pair<string,int>PSI; typedef pair<string,string>PSS; const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353; const int MAXN=1e8+5; const double eps=1e-9; const int dx[4]={-1,1,0,0}; const int dy[4]={0,0,-1,1}; void solve() { //1234 //3412 int n; cin>>n; vector<int>a(n+1),b(n+1); for(int i=1;i<=n;++i){ cin>>a[i]; } for(int i=1;i<=n;++i){ int x; cin>>x; b[x]=i; } int ans=INF; for(int i=1;i<=n;++i){ int c=abs(i-b[a[i]]); if(c==0&&(i==1||i==n))continue; if(c==0)c++; ans=min(ans,c); } if(ans==INF)cout<<-1<<'\n'; else cout<<min(2ll,ans)<<'\n'; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int t=1; cin>>t; while(t--){ solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现