1001:Age of Moyu
1002:AraBellaC
枚举循环周期,对每个循环周期内的mxa,mnb,mxb,mnc二分寻找,要保证(mxa-1)%len<(mnb-1)%len和(mxb-1)%len<(mnc-1)%len。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <cmath> #include <vector> #include <iostream> #include <stack> #include <set> #include <map> using namespace std; const int MAX=1e5+5; int t,m; int a,b,c; vector<int> E[3]; void update(int aa,int bb,int cc){ int flag=0; if(aa<a) flag=1; else if(aa==a&&bb<b) flag=1; else if(aa==a&&bb==b&&cc<c) flag=1; if(flag) a=aa,b=bb,c=cc; } int main(){ int i,j; //freopen("data.in","r",stdin); scanf("%d",&t); while(t--){ int mx=0; a=b=c=0x3f3f3f3f; for(i=0;i<3;i++) E[i].clear(),E[i].push_back(0); scanf("%d",&m); for(i=0;i<m;i++){ int pos;char c; scanf("%d %c",&pos,&c); E[c-'A'].push_back(pos); mx=max(mx,pos); } for(i=0;i<3;i++) E[i].push_back(MAX),sort(E[i].begin(),E[i].end()); for(i=1;i<=mx;i++){ int mxa=0,mnc=MAX,mxb=0,mnb=MAX; for(j=(mx+i-1)/i;j>0;j--){ int tmp=*(upper_bound(E[0].begin(),E[0].end(),j*i)-1); if(tmp>(j-1)*i) mxa=max(mxa,(tmp-1)%i); tmp=*upper_bound(E[1].begin(),E[1].end(),(j-1)*i); if(tmp<=j*i) mnb=min(mnb,(tmp-1)%i); tmp=*(upper_bound(E[1].begin(),E[1].end(),j*i)-1); if(tmp>(j-1)*i) mxb=max(mxb,(tmp-1)%i); tmp=*upper_bound(E[2].begin(),E[2].end(),(j-1)*i); if(tmp<=j*i) mnc=min(mnc,(tmp-1)%i); if(mxa>=mnb||mxb>=mnc) break; } if(j==0) update(mxa+1,mxb-mxa,i-mxb-1); } if(a==0x3f3f3f3f) puts("NO"); else printf("%d %d %d\n",a,b,c); } return 0; }
1005:GuGuFishtion
首先推公式,欧拉函数是积性函数但不是一个完全积性函数,所以a,b不互质的情况下肯定还有一个偏移量。然后质因数分解一下a,b可以用数论知识证明差一个GCD(a,b)/Φ(GCD(a,b)),所以对于所有a,b不互质的情况下对答案的贡献是GCD(a,b)/Φ(GCD(a,b)),互质的话贡献是1。然后容斥,枚举k,容斥计算以k作为gcd的数对有多少个,然后乘上贡献就行了。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=1000000+5; LL tmp,ans; long long n,m,p; long long phi[N], cnt, prime[N/3],dy[N], val[N], q[N],sum_val[N],sum[N],inv[N],mu[N]; bool com[N]; int primes; void get_prime_phi(){ memset( com, false, sizeof( com ) ); primes = 0; phi[1] = 1; mu[1] = 1; for (int i = 2; i < N; ++i){ if (!com[i]) { prime[primes++] = i; phi[i] = i-1; mu[i] = -1; } for (int j = 0; j < primes && i*prime[j] <= N; ++j){ com[i*prime[j]] = true; if (i % prime[j]){ phi[i*prime[j]] = phi[i]*(prime[j]-1); mu[i*prime[j]] = -mu[i]; } else { mu[i*prime[j]] = 0; phi[i*prime[j]] = phi[i]*prime[j]; break; } } } } int lim; long long f[N],F[N]; void get(){ for(int i=1;i<=lim;++i) F[i]=1ll*(m/i)*(n/i)%p; for(int i=lim;i>0;--i){ f[i]=F[i]; for(int j=i+i;j<=lim;j+=i) f[i]-=1ll*f[j]%p; } for(int i=1;i<=lim;++i) f[i]%=p; } int main(){ //freopen("case.in","r",stdin); int T; scanf("%d",&T); get_prime_phi(); while(T--){ scanf("%lld%lld%lld",&n,&m,&p); tmp=ans=0; lim=min(n,m); memset(inv,0,sizeof(inv)); memset(f,0,sizeof(f)); inv[1]=1; for(register int i=2;i<=lim+2;i++) inv[i]=(LL)(p-p/i)*inv[p%i]%p; get(); for(register int i=1;i<=lim;i++){ val[i]=(LL)i*inv[phi[i]]%p; ans=(ans+(LL)val[i]*f[i]%p)%p; if(ans<0) ans+=p; //cout<<ans<<endl; } printf("%lld\n",ans); } return 0; }
1006:Lord Li's problem
有意思的dp;
根据异或的性质,X_0⊕X_1⊕X_2⊕X_3⊕…..⊕X_(M-1)=S⊕T
计算出S⊕T中一共有cnt个1,将这个二进制数标准化,使它成为前面N-cnt个0,后cnt个1的二进制数,答案保持不变,问题变为:用K个N位且有3个1的不同二进制数进行异或,最终得到前面N-cnt个0,后面cnt个1这个二进制数,有多少种方案?
递推。设d[K][M]表示用K个N位且有3个1的不同二进制数进行异或,最终得到前面N-cnt个0,后面cnt个1这个二进制数的方案数。
然后可以容易推出状态只可以从上一层的-1,-3,+1,+3这些状态转移过来
考虑加入重复串的影响,d[i][j]-= (d[i-2][j] * (C[n][3]-i+2);表示去除加入i-2个数字并且后面有j个1这个二进制数但后来又异或上两个之前没用过的相同的数的方案数,
考虑二进制数加入的先后顺序给答案带来的额外贡献,d[i][j]=d[i][j]*inv[i]%mod
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; const long long mod=19260817; long long dp[30][50],c[50][50],inv[110]; char S[45],T[45]; int n,k; void init() { memset(dp,0,sizeof(dp)); } int main() { int i,j; c[0][0]=1; for(i=1;i<=45;i++) { c[i][0]=c[i][i]=1; for(j=1;j<i;j++) { c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; } } inv[1]=1; for(i=2;i<=60;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; int cas=1; while(scanf("%d%d",&n,&k)!=EOF) { if(n==0&&k==0) break; init(); scanf("%s%s",S,T); int num_1=0; for(i=0;i<n;i++) if((S[i]-'0')^(T[i]-'0')==1) num_1++; dp[0][0]=1; for(i=1;i<=k;i++) { for(j=0;j<=n;j++) { if(j>=3) dp[i][j]=(dp[i][j]+dp[i-1][j-3]*c[j][3])%mod; if(j>=1) dp[i][j]=(dp[i][j]+dp[i-1][j-1]*c[j][2]%mod*c[n-j][1])%mod; if(j+3<=n) dp[i][j]=(dp[i][j]+dp[i-1][j+3]*c[n-j][3])%mod; if(j+1<=n) dp[i][j]=(dp[i][j] + dp[i - 1][j + 1] * c[j][1] %mod* c[n - j][2]) % mod; if (i - 2 >= 0)dp[i][j] = (dp[i][j] - (dp[i - 2][j] * (c[n][3] - i + 2))) % mod; dp[i][j] = dp[i][j] * inv[i] % mod; if(dp[i][j]<0) dp[i][j]+=mod; } } printf("Case #%d: %lld\n",cas++, dp[k][num_1]); } return 0; }
1007:Reverse Game
1008:Traffic Network in Numazu
1009:
1010:
矩阵快速幂,首先可以看出这题只能用矩阵快速幂,然后考虑对p进行分块,处理出p/i这个矩阵的指数,然后就矩阵快速幂了
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <cmath> #include <vector> #include <iostream> #include <stack> #include <set> #include <map> using namespace std; const int MAX=5; const int mod=1e9+7; struct Matrix{ long long mp[MAX][MAX]; //矩阵 int n,m; //行 列 Matrix(int _n,int _m){ n=_n,m=_m; for(int i=0;i<n;i++) for(int j=0;j<m;j++) mp[i][j]=0; } Matrix operator+(const Matrix &b)const{ Matrix tmp(n,m); for(int i=0;i<n;i++) for(int j=0;j<m;j++){ tmp.mp[i][j]=mp[i][j]+b.mp[i][j]; tmp.mp[i][j]%=mod; } return tmp; } Matrix operator*(const Matrix &b)const{ Matrix ret(n,b.m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) for(int k=0;k<m;k++){ ret.mp[i][j]+=mp[i][k]*b.mp[k][j]; ret.mp[i][j]%=mod; } return ret; } Matrix operator^(long long k)const{ Matrix ret(n,m),b(n,m); for(int i=0;i<n;i++){ for(int j=0;j<m;j++) b.mp[i][j]=mp[i][j]; ret.mp[i][i]=1; } while(k){ if(k&1) ret=ret*b; b=b*b; k>>=1; } return ret; } }; int t; int a,b,c,d,p,n; int main(){ int i; scanf("%d",&t); while(t--){ scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&p,&n); if(n==1) printf("%d\n",a); else if(n==2) printf("%d\n",b); else{ Matrix mc(3,1); mc.mp[0][0]=b; mc.mp[1][0]=a; mc.mp[2][0]=1; int now=3; Matrix mb(3,3); mb.mp[0][0]=d,mb.mp[0][1]=c,mb.mp[1][0]=1,mb.mp[2][2]=1; while(now<=n){ int tmp=p/now; mb.mp[0][2]=tmp; if(tmp==0){ mc=(mb^(n-now+1))*mc; break; } int x=p/tmp; if(x>n) x=n; mc=(mb^(x-now+1))*mc; now=x+1; } printf("%lld\n",mc.mp[0][0]); } } return 0; }
1011:
瞎贪就行,按每个关键字开优先队列,直到从最后一个队列弹出表示可以击杀,同时加上exp就好。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <cmath> #include <vector> #include <iostream> #include <stack> #include <set> #include <map> using namespace std; struct FastIO { static const int S = 200; int wpos; char wbuf[S]; FastIO() :wpos(0) {} inline int xchar() { static char buf[S]; static int len = 0, pos = 0; if (pos == len) pos = 0, len = fread(buf, 1, S, stdin); if (pos == len) exit(0); return buf[pos++]; } inline int read() { int s = 1, c = xchar(), x = 0; while (c <= 32) c = xchar(); if (c == '-') s = -1, c = xchar(); for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0'; return x * s; } ~FastIO() { if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0; } }io; const int MAX=1e5+5; int t,n,k,ans; struct node{ int x[10],y[10]; }mon[MAX]; int v[10]; struct cmpa{ bool operator()(node a,node b){ return a.x[0]>b.x[0]; } }; struct cmpb{ bool operator()(node a,node b){ return a.x[1]>b.x[1]; } }; struct cmpc{ bool operator()(node a,node b){ return a.x[2]>b.x[2]; } }; struct cmpd{ bool operator()(node a,node b){ return a.x[3]>b.x[3]; } }; struct cmpe{ bool operator()(node a,node b){ return a.x[4]>b.x[4]; } }; priority_queue<node,vector<node>,cmpa> a; priority_queue<node,vector<node>,cmpb> b; priority_queue<node,vector<node>,cmpc> c; priority_queue<node,vector<node>,cmpd> d; priority_queue<node,vector<node>,cmpe> e; int main(){ int i,j; //freopen("1.in","r",stdin); //freopen("10.out","w",stdout); t=io.read(); while(t--){ ans=0; while(!a.empty()) a.pop(); while(!b.empty()) b.pop(); while(!c.empty()) c.pop(); while(!d.empty()) d.pop(); while(!e.empty()) e.pop(); n=io.read(),k=io.read(); for(i=0;i<k;i++) v[i]=io.read(); for(i=0;i<n;i++){ for(j=0;j<k;j++) mon[i].x[j]=io.read(); for(j=0;j<k;j++) mon[i].y[j]=io.read(); a.push(mon[i]); } if(k==1){ while(!a.empty()){ node now=a.top(); if(v[0]>=now.x[0]){ ans++; a.pop(); v[0]+=now.y[0]; } else break; } } else if(k==2){ while(!a.empty()){ node now=a.top(); if(v[0]>=now.x[0]){ a.pop(); b.push(now); while(!b.empty()){ node now=b.top(); if(v[1]>=now.x[1]){ ans++; b.pop(); v[0]+=now.y[0]; v[1]+=now.y[1]; } else break; } } else break; } } else if(k==3){ while(!a.empty()){ node now=a.top(); if(v[0]>=now.x[0]){ a.pop(); b.push(now); while(!b.empty()){ node now=b.top(); if(v[1]>=now.x[1]){ b.pop(); c.push(now); while(!c.empty()){ node now=c.top(); if(v[2]>=now.x[2]){ ans++; c.pop(); v[0]+=now.y[0]; v[1]+=now.y[1]; v[2]+=now.y[2]; } else break; } } else break; } } else break; } } else if(k==4){ while(!a.empty()){ node now=a.top(); if(v[0]>=now.x[0]){ a.pop(); b.push(now); while(!b.empty()){ node now=b.top(); if(v[1]>=now.x[1]){ b.pop(); c.push(now); while(!c.empty()){ node now=c.top(); if(v[2]>=now.x[2]){ c.pop(); d.push(now); while(!d.empty()){ node now=d.top(); if(v[3]>=now.x[3]){ ans++; d.pop(); v[0]+=now.y[0]; v[1]+=now.y[1]; v[2]+=now.y[2]; v[3]+=now.y[3]; } else break; } } else break; } } else break; } } else break; } } else if(k==5){ while(!a.empty()){ node now=a.top(); if(v[0]>=now.x[0]){ a.pop(); b.push(now); while(!b.empty()){ node now=b.top(); if(v[1]>=now.x[1]){ b.pop(); c.push(now); while(!c.empty()){ node now=c.top(); if(v[2]>=now.x[2]){ c.pop(); d.push(now); while(!d.empty()){ node now=d.top(); if(v[3]>=now.x[3]){ d.pop(); e.push(now); while(!e.empty()){ node now=e.top(); if(v[4]>=now.x[4]){ ans++; e.pop(); v[0]+=now.y[0]; v[1]+=now.y[1]; v[2]+=now.y[2]; v[3]+=now.y[3]; v[4]+=now.y[4]; } else break; } } else break; } } else break; } } else break; } } else break; } } printf("%d\n",ans); for(i=0;i<k;i++) printf("%d%c",v[i],i==k-1?'\n':' '); } return 0; }