A
签到
#include<bits/stdc++.h> using namespace std; int n,m,s[2],t[2],ans; int main() { scanf("%d%d",&n,&m); for(int i=1,x;i<=n;i++)scanf("%d",&x),s[x&1]++; for(int i=1,x;i<=m;i++)scanf("%d",&x),t[x&1]++; ans=min(s[0],t[1])+min(s[1],t[0]); printf("%d",ans); }
B
要求40次,而log(1e6)≈20,也就是说最多20个二进制位,可以每次翻转最高的“0”位,然后再+1即可。证明:若为11...10...00,则翻转最高0位后直接结束;若为全1,也是直接结束;若后面存在1,翻转后必然存在0,使得最高位向后走。
#include<bits/stdc++.h> using namespace std; int n,m,tim,a[1000]; bool judge(int x) { int flag=1; for(int i=30;i>=0;i--) if(x&(1<<i))flag=0; else if(!flag)return 0; return 1; } int main() { cin>>n; while(!judge(n)) { tim++; if(tim&1) { int flag=1; for(int i=30;i>=0;i--)if(n&(1<<i))flag=0;else if(!flag){a[++m]=i+1;break;} n^=(1<<a[m]+1)-1; } else n++; } printf("%d ",tim); for(int i=1;i<=m;i++)printf("%d ",a[i]); }
C
签到,开始还看成了最大公约数,自闭。其实就是枚举差值的每个因数,暴力加一下即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll a,b,d,ans,mn; void work(ll x) { ll t=(x-a%x)%x,A=a+t,B=b+t,g=A/__gcd(A,B)*B; if(g<mn)mn=g,ans=t; else if(g==mn&&t<ans)ans=t; } int main() { cin>>a>>b; if(a==b){cout<<0;return 0;} if(a>b)d=a-b;else d=b-a; mn=a/__gcd(a,b)*b; for(ll i=1;i*i<=d;i++) if(d%i==0)work(i),work(d/i); cout<<ans; }
D
被这题搞自闭了,看到什么最大值对1e9+7取模以为是个神仙题,后来才发现是个SB贪心题,其实就是能选的边尽量选,后来证明了一下:只有一个儿子显然,有两个儿子可以证明:如果自己能选没选,那么两个儿子的边也只能选1个,还会影响后面,如果自己不能选,随机选一个是也是对的。然后可以f[i][j][0/1]表示走了i步,前缀和为j,该点与父亲的边是否被选的节点数有几个,直接暴力转移即可。
#include<bits/stdc++.h> using namespace std; const int N=1007,mod=1e9+7; int n,ans,f[2*N][N][2]; void add(int&x,int y){x=(x+y)%mod;} int main() { scanf("%d",&n); f[1][1][1]=1; for(int i=1;i<=2*n;i++) for(int j=0;j<=n;j++) { int lc=n+1,rc=n+1; if(j+1<=2*n-i-1)lc=j+1; if(j)rc=j-1; if(lc>n&&rc>n)continue; if(f[i][j][0]) { if(lc<=n&&rc<=n)add(f[i+1][lc][1],f[i][j][0]),add(f[i+1][rc][0],f[i][j][0]); else if(lc<=n)add(f[i+1][lc][1],f[i][j][0]); else add(f[i+1][rc][1],f[i][j][0]); } if(f[i][j][1]) { if(lc<=n)add(f[i+1][lc][0],f[i][j][1]); if(rc<=n)add(f[i+1][rc][0],f[i][j][1]); } } for(int i=1;i<=2*n;i++) for(int j=0;j<=n;j++) if(f[i][j][1])add(ans,f[i][j][1]); printf("%d",ans); }
E
被D搞自闭了,E也不会了。其实这道题有一种很神奇的做法:首先当然把b[i]>c[i]的判掉,然后不难发现相邻2个值中一定一个是最大值,另一个是最小值,然后连接(n-1)条(b[i],c[i])的无向边,然后跑一遍欧拉路,若存在长度为n的欧拉路就可以输出解了。
#include<bits/stdc++.h> using namespace std; const int N=2e5+7; int n,m,cnt,tot,a[N],b[N],c[N],w[N],hd[N],v[N<<1],nxt[N<<1],vis[N],du[N]; map<int,int>id; void add(int x,int y) { v[++cnt]=y,nxt[cnt]=hd[x],hd[x]=cnt,du[x]++; v[++cnt]=x,nxt[cnt]=hd[y],hd[y]=cnt,du[y]++; } int getid(int x) { if(!id[x])w[id[x]=++tot]=x; return id[x]; } void euler(int u) { for(int &i=hd[u];i;i=nxt[i]) if(!vis[i>>1])vis[i>>1]=1,euler(v[i]); a[++m]=u; } int main() { scanf("%d",&n); for(int i=1;i<n;i++)scanf("%d",&b[i]); for(int i=1;i<n;i++)scanf("%d",&c[i]); cnt=1; for(int i=1;i<n;i++) if(b[i]>c[i]){puts("-1");return 0;} else add(getid(b[i]),getid(c[i])); int S=1,num=0; for(int i=1;i<=tot;i++)if(du[i]&1)S=i,num++; if(num&&num!=2){puts("-1");return 0;} euler(S); if(m!=n){puts("-1");return 0;} for(int i=1;i<=n;i++)printf("%d ",w[a[i]]); }
F
神仙题,看某AC代码写了F1,大概是f[i][j][k]表示长为i,走j步,后面覆盖集合为k的方案数,直接根据题意转移状态。后来发现F2也没意思就是一样的做法,加个矩阵快速幂就行了,不过懒得写了。
#include<bits/stdc++.h> using namespace std; const int N=1e5+7,mod=1e9+7; int n,k,m,ans,sz[25],f[N][13][16]; int main() { scanf("%d%d%d",&n,&k,&m); for(int i=1;i<1<<m;i++)sz[i]=sz[i>>1]+(i&1); f[1][1][1]=1; for(int i=1;i<=n;i++) { for(int j=0;j<k;j++) for(int S=0;S<1<<m;S++) if(f[i][j][S]) { int nS=((S<<1)&((1<<m)-1)); f[i+1][j][nS]=(f[i+1][j][nS]+f[i][j][S])%mod; f[i+1][j+1][nS|1]=(f[i+1][j+1][nS|1]+1ll*f[i][j][S]*(sz[S]+1))%mod; } int sum=0; for(int S=0;S<(1<<m);S++)sum=(sum+f[i][k][S])%mod; ans=(ans+1ll*sum*(n-i+1))%mod; } printf("%d",ans); }
新号打的,初始语言默认C差评,被卡了十几分钟CE不知道,十分不爽。
result:rank95 rating+=225 now_rating=1725