Codeforces357
A.Group of Students
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXM=100+2; int M,a[MAXM],x,y; int main(){ cin >> M; for(int i=1;i<=M;i++) scanf("%d",a+i),a[i]+=a[i-1]; cin >> x >> y; for(int i=2,s,t;i<=M;i++){ s=a[i-1],t=a[M]-a[i-1]; if(x<=s && s<=y && x<=t && t<=y){ cout << i << endl; return 0; } } cout << 0 << endl; return 0; }
B.Flag Day
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=100000+2; int N,M,r[MAXN]; int main(){ cin >> N >> M; for(int i=1,a,b,c;i<=M;i++){ cin >> a >> b >> c; if(!r[a] && !r[b] && !r[c]) r[a]=1,r[b]=2,r[c]=3; else if(r[a]==1) r[b]=2,r[c]=3; else if(r[b]==1) r[a]=2,r[c]=3; else if(r[c]==1) r[a]=2,r[b]=3; else if(r[a]==2) r[b]=1,r[c]=3; else if(r[b]==2) r[a]=1,r[c]=3; else if(r[c]==2) r[a]=1,r[b]=3; else if(r[a]==3) r[b]=1,r[c]=2; else if(r[b]==3) r[a]=1,r[c]=2; else if(r[c]==3) r[a]=1,r[b]=2; } for(int i=1;i<=N;i++) cout << r[i] << " "; cout << endl; return 0; }
C.Knight Tournament
题意:N个人参加M场比赛,每场比赛为[li,ri]之间,且未被淘汰的人比拼,每场比赛只有一个胜者,已知每场比赛的胜者xi,求某个人是被谁打败的。
题解:模拟很显然,问题在于如何优化更新的过程,由于是区间修改,单点修改,所以可以想到用线段树来维护。由于先进行的比赛优先级更高,所以我们从后向前更新,每次更新[li,xi-1],[xi+1,ri](因为xi还未被打败)。
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=300000+2; const int MAXM=300000+2; struct NODE{ int l,r,v; }t[6*MAXN]; int N,M,l[MAXM],r[MAXM],x[MAXM]; void Pushdown(int x){ if(!t[x].v) return; t[2*x].v=t[2*x+1].v=t[x].v; t[x].v=0; } void Build(int x,int l,int r){ t[x].l=l,t[x].r=r,t[x].v=0; if(l==r) return; int m=(l+r)>>1; Build(2*x,l,m),Build(2*x+1,m+1,r); } void Update(int x,int l,int r,int v){ if(r<l) return; if(l<=t[x].l && t[x].r<=r){ t[x].v=v; return; } Pushdown(x); int m=(t[x].l+t[x].r)>>1; if(l<=m) Update(2*x,l,r,v); if(r>m) Update(2*x+1,l,r,v); } int Query(int x,int p){ if(t[x].l==t[x].r) return t[x].v; Pushdown(x); int m=(t[x].l+t[x].r)>>1; if(p<=m) return Query(2*x,p); else return Query(2*x+1,p); } int main(){ cin >> N >> M; Build(1,1,N); for(int i=1;i<=M;i++) scanf("%d %d %d",l+i,r+i,x+i); for(int i=M;i;i--){ Update(1,l[i],x[i]-1,x[i]); Update(1,x[i]+1,r[i],x[i]); } for(int i=1,x;i<=N;i++){ x=Query(1,i); if(x==i) cout << 0 << " "; else cout << x << " "; } return 0; }
D.Xenia and Hamming
题意:给定两个长度相同的字符串A B,两者分别由循环节x y构成,求A B的字符不同的位置的个数。
题解:最先想到的是用lcm(L(x),L(y)),暴力算出一个的,但是显然会T。显然统计相同的位数会更简单一些,考虑性质:假如A[i]和B[j]有概率匹配,当且仅当i≡j(mod gcd(L(x),L(y))),所以对于每一位,我们只需要考虑其mod gcd后的位置即可。因此我们改变枚举的方式,改为枚举余数。
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long const int MAXL=1000000+2; const int MAXK=26+2; ll N,M,C,LS,LT,G,L,RS[MAXL][MAXK]; char S[MAXL],T[MAXL]; ll gcd(ll a,ll b){ if(a<b) swap(a,b); return (b?gcd(b,a%b):a); } int main(){ cin >> N >> M; scanf("%s %s",S,T); LS=strlen(S),LT=strlen(T); G=gcd(LS,LT),L=LS*LT/G; for(int i=0;S[i];i++) RS[i%G][S[i]-'a']++; for(int i=0;T[i];i++) C+=RS[i%G][T[i]-'a']; cout << N*LS-N*LS/L*C; return 0; }
E.Compartments
(待补)