Codeforces Round #713 (Div. 3)(A~G)(埃氏筛,dp)
A. Spy Detected!
找到只有1个的数就行
AC代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<map> #include<sstream> #define MAXN 50005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int t,n; int a[105],vis[105]; int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); memset(vis,0,sizeof(vis)); int temp1=0,temp2=0,ans=0,cnt=0;; int flag=0; for(int i=0;i<n;i++){ scanf("%d",&a[i]); vis[a[i]]++; if(vis[a[i]]==1){ if(!temp1) temp1=i+1; else if(!temp2) temp2=i+1; }else if(vis[a[i]]>1&&!flag){ if(!temp2){ flag=2; }else if(a[i]==a[temp1-1]){ flag=2; }else if(a[i]==a[temp2-1]){ flag=1; } } } if(flag==1) printf("%d\n",temp1); else{ printf("%d\n",temp2); } } return 0; }
B. Almost Rectangle
根据给定的两个*的位置构造矩形即可。
AC代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<map> #include<sstream> #define MAXN 50005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int t,n; char m[405][405]; int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%s",m[i]+1); int tempx1=0,tempx2=0,tempy1,tempy2; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(m[i][j]=='*'){ if(!tempx1){ tempx1=i,tempy1=j; }else{ tempx2=i,tempy2=j; } } if(tempx1!=tempx2&&tempy1!=tempy2){ m[tempx1][tempy2]='*'; m[tempx2][tempy1]='*'; }else if(tempx1==tempx2){ if(tempx1!=n){ m[tempx1+1][tempy1]='*'; m[tempx1+1][tempy2]='*'; }else{ m[tempx1-1][tempy1]='*'; m[tempx1-1][tempy2]='*'; } }else if(tempy1==tempy2){ if(tempy1!=n){ m[tempx1][tempy1+1]='*'; m[tempx2][tempy2+1]='*'; }else{ m[tempx1][tempy1-1]='*'; m[tempx2][tempy2-1]='*'; } } for(int i=1;i<=n;i++) printf("%s\n",m[i]+1); } return 0; }
C. A-B Palindrome
先判断能否构成,再根据0和1的数量和?的对应关系判断即可。
AC代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<map> #include<sstream> #define MAXN 200005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int t,n,a,b; char m[MAXN]; int pos[MAXN]; int judge(){ for(int i=0;i<n/2;i++){ if(m[i]!=m[n-1-i]&&m[i]!='?'&&m[n-1-i]!='?'){ return 0; } } return 1; } int main(){ scanf("%d",&t); while(t--){ memset(m,0,sizeof(m)); memset(pos,0,sizeof(pos)); scanf("%d%d",&a,&b);//a个0,b个1 n=a+b; scanf("%s",m); if(((a&1)&&(b&1))||!judge()){//先判断原来能不能构成回文串 printf("-1\n"); }else if(n==1&&(a+b)==1&&m[0]=='?'){//特判只有一个?的请况 if(a) printf("0\n"); else if(b) printf("1\n"); }else{ int cnt=0; for(int i=0;i<n/2;i++){ if(m[i]=='?'&&m[n-1-i]=='?'){ pos[cnt++]=i; }else if(m[i]=='?'){ m[i]=m[n-i-1]; if(m[i]=='0') a-=2; else b-=2; }else if(m[n-i-1]=='?'){ m[n-i-1]=m[i]; if(m[i]=='0') a-=2; else b-=2; }else{ if(m[i]=='0') a-=2; else b-=2; } } int dan=0; if(n&1){ if(m[n/2]=='1'){ b--; }else if(m[n/2]=='0') a--; else if(m[n/2]=='?') dan=n/2; } if(!a&&!b&&!dan&&!cnt){//如果全部构造完了 if(a==0&&b==0) printf("%s\n",m); else printf("-1\n"); }else if((a+b)!=2*cnt+(dan>0?1:0)){ printf("-1\n"); }else{ if(dan==0){ if((a&1)||(b&1)){ printf("-1\n"); continue;; } for(int i=0;i<cnt;i++){ if(a){ m[pos[i]]=m[n-pos[i]-1]='0'; a-=2; }else{ m[pos[i]]=m[n-pos[i]-1]='1'; b-=2; } } if(a==0&&b==0) printf("%s\n",m); else printf("-1\n"); }else{ if(a&1){ m[n/2]='0'; --a; }else if(b&1){ m[n/2]='1'; --b; } if((a&1)||(b&1)){ printf("-1\n"); continue; }else{ for(int i=0;i<cnt;i++){ if(a){ m[pos[i]]=m[n-pos[i]-1]='0'; a-=2; }else{ m[pos[i]]=m[n-pos[i]-1]='1'; b-=2; } } if(a==0&&b==0) printf("%s\n",m); else printf("-1\n"); } } } } } return 0; }
D. Corrupted Array
先计算出所有数的总和。再判断是总和减去一个数后是否为数列中某个数的两倍。如果是的话则该数为加上的数,额外的数为减去的那个数
需要特别注意的是需要判断减去的那个数是不是该数。若是的话则需要判断该数出现了几次
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<map> #include<unordered_map> #include<sstream> #define MAXN 200005 #define MAXM 1000000005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int t,n; ll s; ll b[MAXN]; unordered_map<ll,int>vis; int main(){ scanf("%d",&t); while(t--){ vis.clear(); memset(b,0,sizeof(b)); s=0; scanf("%d",&n); for(register int i=0;i<n+2;++i){ scanf("%lld",&b[i]); ++vis[b[i]]; s+=b[i]; } int flag=0,ans; ll temp; for(register int i=0;i<n+2;++i){ temp=s-b[i]; if(temp&1) continue; else temp/=2; if(temp<MAXM){ if(vis[temp]&&temp!=b[i]){//如果减去的不是temp,且temp出现过 flag=1; ans=i; break; }else if(vis[temp]>1&&temp==b[i]){//如果减去的是temp且temp出现了不止一次 flag=1; ans=i; break; } } } if(!flag) printf("-1\n"); else{ for(register int i=0;i<ans;++i){ if(b[i]==temp&&flag){ flag=0; continue; } printf("%lld ",b[i]); } for(register int i=ans+1;i<n+2;++i){ if(b[i]==temp&&flag){ flag=0; continue; } printf("%lld ",b[i]); } printf("\n"); } } return 0; }
E. Permutation by Sum
先计算l~r中能存的数的数目cnt。
那么min=1+……+cnt,max=n-cnt+1+……n。
如果s在min和max之间,那么则可以构造出一个l~r的序列的和为s。
接下来构造即可。剩余位置随便填
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<map> #include<unordered_map> #include<sstream> #define MAXN 200005 #define MAXM 1000000005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int t,n,l,r,s; int vis[505],ans[505]; //unordered_map<ll,int>vis; int main(){ scanf("%d",&t); while(t--){ memset(vis,0,sizeof(vis)); memset(ans,0,sizeof(ans)); scanf("%d%d%d%d",&n,&l,&r,&s); int cnt=r-l+1; int minn=(1+cnt)*cnt/2,maxn=(n+n-cnt+1)*cnt/2; if(s<minn||s>maxn){ printf("-1\n"); }else{ int cha=s-minn; int temp=cha/cnt; int min_ind=cnt,max_ind=n+1,mid_val=n+1; while(1){ if(max_ind-min_ind-1>=cha){ mid_val=min_ind+cha; min_ind--; break; }else{ min_ind--; max_ind--; cha-=(max_ind-min_ind-1); } } cnt=l; for(int i=1;i<=min_ind;++i){ vis[i]=1; ans[cnt]=i; ++cnt; } if(mid_val!=n+1){ vis[mid_val]=1; ans[cnt]=mid_val; ++cnt; } for(int i=max_ind;i<=n;++i){ vis[i]=1; ans[cnt]=i; ++cnt; } cnt=1; for(int i=1;i<l;i++){ while(vis[cnt]) ++cnt; vis[cnt]=1; ans[i]=cnt; ++cnt; } for(int i=r+1;i<=n;i++){ while(vis[cnt]) ++cnt; vis[cnt]=1; ans[i]=cnt; ++cnt; } for(int i=1;i<=n;i++) printf("%d ",ans[i]); printf("\n"); } } return 0; }
F. Education
如果我们要到一个岗位上工作到买电脑,那么则越早到那个岗位越好。(因为工资必定会增加)
所以我们记录每个一直在每个岗位上工作直到买到电脑的日期即可。
求出最短的那个即可。
AC代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<map> #include<unordered_map> #include<sstream> #define MAXN 200005 #define MAXM 1000000005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int t,n,c; int a[MAXN],b[MAXN];//ans表示答案,sav表示到下一个岗位的存款,d表示天数 int main(){ scanf("%d",&t); while(t--){ scanf("%d%d",&n,&c); for(register int i=0;i<n;++i) scanf("%d",&a[i]); for(register int i=0;i<n-1;++i) scanf("%d",&b[i]); b[n-1]=0; ll sav=0,cur=0,ans=1e18; for(register int i=0;i<n;++i){ ans=min(ans,cur+max(0ll,c-sav+a[i]-1)/a[i]); ll ex=max(0ll,b[i]-sav+a[i]-1)/a[i];//为了到达这个职位需要存多少天的钱 cur+=ex+1;//加上到达职位的天数 sav+=a[i]*ex-b[i];//剩余存款 } printf("%lld\n",ans); } return 0; }
G. Short Task
预处理每个数的因子和即可。
可以用埃氏筛计算出该数的一个因子。
如果该数为质数,则d[i]=i+1.
如果不为质数,则先计算出这个因子所带来的影响,并且将这个因子除出这个数,
并且运用:d(a⋅b)=d(a)⋅d(b) if gcd(a,b)=1.来加速运算。
AC代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<map> #include<unordered_map> #include<sstream> #define MAXN 10000005 #define MAXM 1000000005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int t,n,c; int d[MAXN],s[MAXN],ans[MAXN];//ans表示答案,sav表示到下一个岗位的存款,d表示天数 int main(){ d[1]=1; for(register int i=2;i*i<MAXN;++i){ if(!d[i]){ d[i]=i; for(register int j=i*i;j<MAXN;j+=i) if(!d[j]) d[j]=i;//存该数的最小因子 } } s[1]=1; for(register int i=2;i<MAXN;++i){ if(!d[i]){ d[i]=i; s[i]=i+1; }else{ int j=i; s[i]=1; while(j%d[i]==0){ j/=d[i]; s[i]=s[i]*d[i]+1;//相当于加上这个因子的所有幂次 } s[i]*=s[j];//i和j互质。且j小于i,所以s[j]之前肯定被计算过了 } } memset(ans,-1,sizeof(ans)); for(register int i=MAXN-1;i>0;--i) if(s[i]<MAXN) ans[s[i]] =i;//ans为s【i】的逆数组 scanf("%d",&t); while(t--){ int c; scanf("%d",&c); printf("%d\n",ans[c]); } return 0; }

浙公网安备 33010602011771号