2017ccpc杭州站题解
A 贪心,找奇偶数分别最大
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; int a[30]; int b[30]; int main(){ ios::sync_with_stdio(false); int i; int t; cin>>t; while(t--){ string s; cin>>s; memset(a,0,sizeof a); memset(b,0,sizeof b); int cnt=(int)s.size(); s=" "+s; for(i=1;i<(int)s.size();i++){ int sign=s[i]-'a'; if(i%2){ a[sign]++; } else{ b[sign]++; } } int mx1=0,mx2=0; for(i=0;i<26;i++){ mx1=max(mx1,a[i]); mx2=max(mx2,b[i]); } cout<<cnt-mx1-mx2<<endl; } return 0; }
B模拟
#include<cstdio> #define LL long long using namespace std; const int mod=998244353; LL qpow(LL m,LL k) { LL res=1%mod; LL t=m%mod; while(k) { if(k&1) res=res*t%mod; t=t*t%mod; k>>=1; } return res%mod; } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); LL ans=1; for(int i=1;i<=n;i++) { LL p,q; scanf("%lld%lld",&p,&q); LL tmp=((qpow(p,q-1)*(p-1))%mod*q)%mod; ans=(ans*(qpow(p,q)+tmp)%mod)%mod; } printf("%lld\n",ans); } return 0; }
C博弈,与%3相同
#include<cstdio> using namespace std; int a[1000005]; int main() { int T; scanf("%d",&T); while(T--) { int n,d; scanf("%d%d",&n,&d); int sum=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]==1) sum++; } if(d==1) { if(n%3==0&&sum==n) printf("No\n"); else printf("Yes\n"); } else { if(n%3==1&&sum>=n-1) printf("No\n"); else if(n%3==0&&sum==n-1) printf("No\n"); else printf("Yes\n"); } } return 0; }
D找规律
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; const ll mod=998244353; ll a[N]; ll f[N]; ll fac[123456]; ll qmi(ll a,ll b){ a%=mod; ll res=1; while(b){ if(b&1){ res=res*a%mod; } b>>=1; a=a*a%mod; } return res; } int main(){ fac[0]=1; for(ll i=1;i<=100005;i++) fac[i]=fac[i-1]*i%mod; f[1]=2; f[0]=1; ll g=1; for(int i=2;i<=100005;i++){ f[i]=(2*f[i-1]%mod+g)%mod; g=g*2%mod; } ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n; cin>>n; int i; for(i=0;i<=n-1;i++){ cin>>a[i]; } ll tmp=fac[n-1]*a[0]%mod; ll t=fac[n-1]; for(i=1;i<=n-1;i++){ t=t+fac[n-1]*qmi(i,mod-2)%mod; t%=mod; tmp=(tmp+a[i]*t)%mod; } ll sum=fac[n]; cout<<tmp*qmi(sum,mod-2)%mod<<endl; } return 0; }
E点分治+bitset(观察数据范围只有3000可猜测)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e5+10; const int mod=1e7+7; int n,idx; int h[N],ne[N],e[N],w[N]; int cnt[N],vis[N],d[N],sz[N]; int dis[N]; int st[N]; int root; int m; bitset<100010> bit[3030],ans; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs_root(int u,int fa,int tot){ int i; sz[u]=1; int ans=0; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||vis[j]) continue; dfs_root(j,u,tot); sz[u]+=sz[j]; ans=max(ans,sz[j]); } ans=max(ans,tot-sz[u]); if(ans*2<=tot){ root=u; } } void dfs_sz(int u,int fa){ sz[u]=1; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||vis[j]) continue; dfs_sz(j,u); sz[u]+=sz[j]; } } void get(int u,int fa){ bit[u]<<=w[u]; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||vis[j]) continue; bit[j]=bit[u]; get(j,u); bit[u]|=bit[j]; } } void work(int u,int tot){ dfs_root(u,-1,tot); u=root; vis[u]=1; dfs_sz(u,-1); bit[u].reset(); bit[u].set(0); get(u,-1); ans|=bit[u]; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(vis[j]) continue; work(j,sz[j]); } } int main(){ //ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n; scanf("%d%d",&n,&m); int i; ans.reset(); idx=0; for(i=0;i<=n;i++){ h[i]=-1; vis[i]=0; } for(i=1;i<n;i++){ int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } for(i=1;i<=n;i++) scanf("%d",&w[i]); work(1,n); for(i=1;i<=m;i++){ printf("%d",(int)ans[i]); } printf("\n"); } return 0; }
J 差分
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; ll mod=998244353; int a[100005]; int b[100005]; ll ksm(ll x,ll y){ ll res=1; while(y){ if(y&1)res=res*x%mod; x=x*x%mod; y>>=1; } return res%mod; } int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); memset(a,0,sizeof a); memset(b,0,sizeof b); while(m--){ int l,r,x; scanf("%d%d%d",&l,&r,&x); if(x==2){ a[l]++;a[r+1]--; } else{ b[l]++;b[r+1]--; } } int sa,sb; sa=sb=10000000; for(int i=1;i<=n;i++){ a[i]=a[i-1]+a[i]; b[i]=b[i-1]+b[i]; sa=min(sa,a[i]); sb=min(sb,b[i]); } ll res=1; res=ksm(2,sa)%mod*ksm(3,sb)%mod; cout<<res<<endl; } }
K 二分+预处理
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; const ll inf=1e15; typedef long long ll; int n,m; ll sum[2020][2020]; int a[N],b[N]; ll ans=0; bool check(ll x,ll y){ ll res=0; for(int i=1;i<=1000;i++){ res+=sum[i][0]*(x/i); res-=sum[i][x%i+1]; } return res>=y; } ll solve(ll x){ ll l=1,r=inf; while(l<r){ ll mid=l+r>>1; if(check(mid,x)){ r=mid; } else{ l=mid+1; } } return l; } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>n>>m; int i,j; ans=0; for(i=1;i<=1000;i++){ for(j=0;j<=1000;j++) sum[i][j]=0; } for(i=1;i<=n;i++){ cin>>a[i]; } for(i=1;i<=n;i++){ cin>>b[i]; } for(i=1;i<=n;i++){ sum[a[i]][b[i]%a[i]]++; ans+=b[i]/a[i]; } for(i=1;i<=1000;i++){ for(j=i-1;j>=0;j--){ sum[i][j]+=sum[i][j+1]; } } while(m--){ int opt; cin>>opt; ll x,y; if(opt==1){ cin>>x>>y; ans-=b[x]/a[x]; ans+=b[x]/y; for(i=b[x]%a[x];i>=0;i--){ sum[a[x]][i]--; } for(i=b[x]%y;i>=0;i--){ sum[y][i]++; } a[x]=y; } else if(opt==2){ cin>>x>>y; ans-=b[x]/a[x]; ans+=y/a[x]; for(i=b[x]%a[x];i>=0;i--){ sum[a[x]][i]--; } for(i=y%a[x];i>=0;i--){ sum[a[x]][i]++; } b[x]=y; } else{ cin>>x; cout<<solve(x+ans)<<endl; } } } }
L 类欧几里得
#include <bits/stdc++.h> #define rint register int #define inv inline void #define ini inline int #define maxn 1000050 using namespace std; typedef long long ll; typedef long long LL; char s[maxn]; int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],wt[30]; //rk代表i的排名,sa代表排名为i的后缀位置 int n,m; inv putout(int x) { if(!x) {putchar(48);return;} rint l=0; while(x) wt[++l]=x%10,x/=10; while(l) putchar(wt[l--]+48); } inv get_SA() { for (rint i=1;i<=n;++i) ++c[x[i]=s[i]];//c数组是桶,x[i]是第i个元素的第一关键字 for (rint i=2;i<=m;++i) c[i]+=c[i-1];//做c的前缀和,我们就可以得出每个关键字最多是在第几名 for (rint i=n;i>=1;--i) sa[c[x[i]]--]=i; for (rint k=1;k<=n;k<<=1) { rint num=0; for (rint i=n-k+1;i<=n;++i) y[++num]=i; //y[i]表示第二关键字排名为i的数,第一关键字的位置 //第n-k+1到第n位是没有第二关键字的 所以排名在最前面 for (rint i=1;i<=n;++i) if (sa[i]>k) y[++num]=sa[i]-k; //排名为i的数 在数组中是否在第k位以后 //如果满足(sa[i]>k) 那么它可以作为别人的第二关键字,就把它的第一关键字的位置添加进y就行了 //所以i枚举的是第二关键字的排名,第二关键字靠前的先入队 for (rint i=1;i<=m;++i) c[i]=0;//初始化c桶 for (rint i=1;i<=n;++i) ++c[x[i]];//因为上一次循环已经算出了这次的第一关键字 所以直接加就行了 for (rint i=2;i<=m;++i) c[i]+=c[i-1];//第一关键字排名为1~i的数有多少个 for (rint i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0; //因为y的顺序是按照第二关键字的顺序来排的 //第二关键字靠后的,在同一个第一关键字桶中排名越靠后 //基数排序 swap(x,y);//这里不用想太多,因为要生成新的x时要用到旧的,就把旧的复制下来,没别的意思 x[sa[1]]=1;num=1; for (rint i=2;i<=n;++i) x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num; //因为sa[i]已经排好序了,所以可以按排名枚举,生成下一次的第一关键字 if (num==n) break; m=num; //这里就不用那个122了,因为都有新的编号了 } for (rint i=1;i<=n;++i) putout(sa[i]),putchar(' '); } inv get_height() { rint k=0; for (rint i=1;i<=n;++i) rk[sa[i]]=i; for (rint i=1;i<=n;++i) { if (rk[i]==1) continue;//第一名height为0 if (k) --k;//h[i]>=h[i-1]+1; rint j=sa[rk[i]-1]; while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k; height[rk[i]]=k;//h[i]=height[rk[i]]; } putchar(10);for (rint i=1;i<=n;++i) putout(height[i]),putchar(' '); } const ll mo=2; LL f(LL a,LL b,LL c,LL n) { if (!a) return (n+1)*(b/c)%mo; if (a>=c || b>=c) { LL sqr=(n&1) ?(n+1)/2*n :n/2*(n+1) ; return (f(a%c,b%c,c,n)+(a/c)*sqr+(n+1)*(b/c))%mo; } else { LL m=(a*n+b)/c; return (m*n-f(c,c-b-1,a,m-1)+mo)%mo; } } int main() { //freopen("../in.in", "r", stdin); // freopen("../out.out","w",stdout); //ios::sync_with_stdio(false); // gets(s+1); // n=strlen(s+1);m=122;//n表示原字符串长度,m表示字符个数,ascll('z')=122 // get_SA(); int t; scanf("%d",&t); while(t--){ ll n; scanf("%lld",&n); ll ans=0,sqrtn=min(30000000ll,n); for(ll i=1;i<=sqrtn;i++) ans^=n%i; for(ll l=sqrtn+1,r;l<=n;l=r+1){ r=n/(n/l); ll ean=0; ll lim=n/l*(r-l)+n%r; for(ll c=1;c<=lim;c<<=1){ if(f(n/l,n%r,c,r-l))ean+=c; } ans^=ean; } printf("%lld\n",ans); } //get_height(); }
没有人不辛苦,只有人不喊疼