Educational Codeforces Round 81 (Rated for Div. 2)
A-Display The Number
题意:
给出0-9所需要的小火柴数量,用小于等于n数量的小火柴搭出最大的数字.
思路:
通过观察可以发现只需考虑1,7的情况.
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3e5+20; int main() { int t;scanf("%d",&t); while(t--) { int n;scanf("%d",&n); if(n==3) printf("7\n"); else { if(n%2==0) printf("1"),n-=2; else printf("7"),n-=3; while(n>=2) printf("1"),n-=2; printf("\n"); } } }
B-Infinite Prefixes
题意:
给定一个由0,1组成的字符串t,求由t组成的循环串中cnt0-cnt1=m的前缀串个数,若无穷输出-1.
思路:
用a[i]表示前i个数中cnt0-cnt1.
首先我们可以从无穷入手,我们很容易可以证明此时cnt1=cnt0.我们只需遍历a[i],搜索是否存在a[i]==m即可.如果存在则输出无穷,否则输出0.
然后对于一般情况只需考虑寻找(a[i]-m)/(cnt0-cnt1)*(cnt0-cnt1)==a[i]-m的个数.
注意m==0的时候空串也可以,需要ans++.
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3e5+20; int tot,cnt,a[maxn]; char s[maxn]; int main() { int T;scanf("%d",&T); while(T--) { tot=cnt=0; int n,m;scanf("%d%d%s",&n,&m,&s); for(int i=0;i<n;i++) if(s[i]=='1') a[++tot]=--cnt; else a[++tot]=++cnt; int flag=1; if(!cnt) for(int i=1;i<=n;i++) if(m-a[i]==0) flag=0; if(!flag) { printf("-1\n"); continue; } if(!cnt) { printf("0\n"); continue; } int ans=0;if(!m) ans++; for(int i=1;i<=n;i++) { int k=m-a[i]; int nt=k/cnt; if(nt<0) continue; if(nt*cnt==k) ans++; } printf("%d\n",ans); } }
C-Obtain The String
题意:
给定字符串s,t.t可以由s的子序列组成,求所需s的个数,若不存在输出-1.
思路:
对于不存在的情况,我们只需判断t中的元素是否都在s中出现.
预处理出s中各个字母的位置,遍历t中的字母,通过upper_bound来O(logn)找出是否存在最早的可行位置,如果不行,cnt++,然后再重新从前往后找.
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+20; char s[maxn],t[maxn]; int zm[30][maxn]; int js[28],jt[28]; int main() { int T;scanf("%d",&T); while(T--) { for(int i=0;i<26;i++) zm[i][0]=js[i]=jt[i]=0; scanf("%s%s",&s,&t); int lens=strlen(s),lent=strlen(t); for(int i=0;i<lens;i++) js[s[i]-'a']=1; for(int i=0;i<lent;i++) jt[t[i]-'a']=1; int flag=0; for(int i=0;i<26;i++) if(jt[i]&&(!js[i])) flag=1; if(flag) { printf("-1\n"); continue; } for(int i=0;i<lens;i++) zm[s[i]-'a'][++zm[s[i]-'a'][0]]=i; int wei=-1; int cnt=1; for(int i=0;i<lent;i++) { int kk=t[i]-'a'; int cur=upper_bound(zm[kk]+1,zm[kk]+zm[kk][0]+1,wei)-zm[kk]; if(cur>zm[kk][0]) cnt++,wei=-1,i--; else wei=zm[kk][cur]; } printf("%d\n",cnt); } }
D-Same GCDs
题意:
给定a,m,求出有多少个x满足 0≤x<m 且 gcd(a,m)=gcd(a+x,m).
思路:
方法一:欧拉公式
设,则
可以得到
由于,则
也就是要找出中与互质的数
根据的性质,我们可以发现等价于找出中与互质的数
这样我们就可以用欧拉函数来求出我们所要的答案,也就是
方法二:容斥
由题意可得我们所要求的是中与m互质的个数
那么子问题就是求中与m互质的个数,这样我们就可以通过找m的质数prime[],再运用容斥定理得出答案
代码1:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3e5+20; ll getphi(ll x){ ll i,j,k,res=x; for(ll i=2;i*i<=x;i++){ if(x%i==0)res=res/i*(i-1); while(x%i==0)x/=i; } if(x>1)res=res/x*(x-1); return res; } int main() { int t;scanf("%d",&t); while(t--) { ll a,m;scanf("%lld%lld",&a,&m); ll ans=getphi(m/__gcd(a,m)); printf("%lld\n",ans); } }
代码2:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1000; ll prime[maxn],tot,a,m,k; ll f(ll x) { ll ans=0; for(int i=1;i<=(1<<tot)-1;i++) { ll cur=1,cnt=0; for(int j=0;j<tot;j++) { if((i>>j)&1) cur*=prime[j+1],cnt++; } if(cnt%2) ans+=x/cur; else ans-=x/cur; } return x-ans; } int main() { int T;scanf("%d",&T); while(T--) { tot=0; scanf("%lld%lld",&a,&m); k=__gcd(a,m);a/=k;m/=k; ll ddd=m; for(ll i=2;i*i<=m;i++) { if(ddd%i==0) prime[++tot]=i; while(ddd%i==0) ddd/=i; } if(ddd!=1)prime[++tot]=ddd; printf("%lld\n",f(a+m-1)-f(a-1)); } }