A:牛牛的方程式
裴蜀定理裸题,注意判断一下gcd=0的情况,剩下然后我们判断一下是否整除
#include<bits/stdc++.h> #define LL long long using namespace std; LL gcd(LL x,LL y){ if(!y)return x; return gcd(y,x%y); } int main(){ int T;scanf("%d",&T); while(T--){ LL x,y,z,d; scanf("%lld%lld%lld%lld",&x,&y,&z,&d); if(x<0)x=-x;if(y<0)y=-y;if(z<0)z=-z; LL g=gcd(x,gcd(y,z)); if(!g){if(d)puts("NO");else puts("YES");} else{if(d%g==0)puts("YES");else puts("NO");} } return 0; }
B:牛牛的猜球游戏
有点小细节,我们只需要维护一个类似于置换的东西就可以了,具体我们可以用st表,线段树,前缀和等方法维护
考试的时候发现细节有点难考虑,直接码上了一个线段树,具体就是线段树的常规操作!
代码:
#include<bits/stdc++.h> #define LL long long using namespace std; const int N=1e5+5; struct swp{int x,y;}a[N]; struct node{int p[10];}t[N<<2]; int n,m,Ans[10]; node merge(node a,node b){ node c; for(int i=0;i<10;i++)c.p[i]=b.p[a.p[i]]; return c; } void build(int rt,int l,int r){ if(l==r){ for(int i=0;i<10;i++)t[rt].p[i]=i; swap(t[rt].p[a[l].x],t[rt].p[a[l].y]); return; } int mid=(l+r)>>1; build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); t[rt]=merge(t[rt<<1],t[rt<<1|1]); } node ask(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R)return t[rt]; int mid=(l+r)>>1; if(R<=mid)return ask(rt<<1,l,mid,L,R); if(L>mid)return ask(rt<<1|1,mid+1,r,L,R); return merge(ask(rt<<1,l,mid,L,R),ask(rt<<1|1,mid+1,r,L,R)); } int read(){ int x=0,c; while(!isdigit(c=getchar())); while(isdigit(c))x=x*10+c-48,c=getchar(); return x; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read(); build(1,1,n); while(m--){ int l=read(),r=read(); node c=ask(1,1,n,l,r); for(int i=0;i<=9;i++)Ans[c.p[i]]=i; for(int i=0;i<=9;i++)printf("%d%c",Ans[i]," \n"[i==9]); } return 0; }
C:牛牛的凑数游戏
考虑mex的一个性质
直接给出结论:我们按照区间中的数排序,如果我们统计直接的mex,如果这个数没有大于之前的mex+1那么我们显然是可以继续拼接下来更新一下新的mex,因此我们有了平方log的做法,然后我们考虑这个过程每次统计的是1个sum,这个增长的速度大约是log或是ln的,于是我们用主席树维护区间的size和sum加速这个模拟的过程就可以了!
接下来是考试的时候的代码,拼了暴力,大家可以看看,或许能帮助更好地理解
代码:
namespace force{ int b[N]; void solve(){ while(m--){ int l,r,tp=0; scanf("%d%d",&l,&r); for(int i=l;i<=r;i++)b[++tp]=a[i]; sort(b+1,b+tp+1); LL lst=0,ans;bool fl=false; for(int i=1;i<=tp;i++){ if(b[i]>lst+1){ans=lst+1;fl=true;break;} lst+=(LL)b[i]; } if(!fl)ans=lst+1; printf("%lld\n",ans); } } } namespace subtask1{ int Root[N],tot,lim=1e9; struct seg{ int siz[N<<6],ls[N<<6],rs[N<<6];LL sum[N<<6]; void insert(int rt,int pre,int l,int r,int x){ siz[rt]=siz[pre]+1;sum[rt]=sum[pre]+(LL)x; if(l==r)return; int mid=(l+r)>>1; ls[rt]=ls[pre];rs[rt]=rs[pre]; (x<=mid)?insert(ls[rt]=++tot,ls[pre],l,mid,x):insert(rs[rt]=++tot,rs[pre],mid+1,r,x); } int asksiz(int rt,int pre,int l,int r,int L,int R){ if(L<=l&&r<=R)return siz[rt]-siz[pre]; int mid=(l+r)>>1,res=0; if(L<=mid)res+=asksiz(ls[rt],ls[pre],l,mid,L,R); if(R>mid)res+=asksiz(rs[rt],rs[pre],mid+1,r,L,R); return res; } LL asksum(int rt,int pre,int l,int r,int L,int R){ if(L<=l&&r<=R)return sum[rt]-sum[pre]; int mid=(l+r)>>1;LL res=0; if(L<=mid)res+=asksum(ls[rt],ls[pre],l,mid,L,R); if(R>mid)res+=asksum(rs[rt],rs[pre],mid+1,r,L,R); return res; } }t; LL query(int l,int r){ int tt=t.asksiz(Root[r],Root[l-1],1,lim,1,1); if(!tt)return 1LL; LL v=tt,nowsiz=tt; while(v<lim){ int newsiz=t.asksiz(Root[r],Root[l-1],1,lim,1,v+1);LL newv; if(newsiz==nowsiz)return v+1; nowsiz=newsiz; newv=t.asksum(Root[r],Root[l-1],1,lim,1,v+1); v=newv; } return t.asksum(Root[r],Root[l-1],1,lim,1,lim)+1; } void solve(){ for(int i=1;i<=n;i++)t.insert(Root[i]=++tot,Root[i-1],1,lim,a[i]); while(m--){ int l,r;scanf("%d%d",&l,&r); printf("%lld\n",query(l,r)); } } }
D:牛牛的RPG游戏
这道题比较裸,就是推一个式子维护一下凸壳,然后具体可以用李超树维护,当然也可以分治维护。
然后考试的时候写了一个关于sqrt(n)有关的复杂度,就是考虑n和m我们用小的当做行数,这样更新是小于根号n的,然后在用李超树查询即可,这样是根号log的,拼上部分分能通过70分,时空复杂度都较大,代码:
#include<bits/stdc++.h> #define LL long long using namespace std; const int N=1e5+5; int n,m; vector<int>b[N],a[N]; void init(){ for(int i=1;i<=n;i++)a[i].resize(m+1),b[i].resize(m+1); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&b[i][j]); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]); } namespace force{ int a[35][35],b[35][35],dp[35][35]; void solve(){ for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&b[i][j]); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)dp[i][j]=a[i][j]; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) for(int lsti=1;lsti<=i;lsti++)for(int lstj=1;lstj<=j;lstj++) if(i!=lsti||j!=lstj)dp[i][j]=max(dp[i][j],dp[lsti][lstj]+b[lsti][lstj]*(i-lsti+j-lstj)+a[i][j]); printf("%d\n",dp[n][m]); } } namespace subtask1{ vector<int>dp[N]; bool check(){ for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(b[i][j])return false; return true; } void solve(){ for(int i=1;i<=n;i++)dp[i].resize(m+1); if(a[1][1]>0)dp[1][1]=a[1][1]; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){ if(i>1)dp[i][j]=max(dp[i][j],dp[i-1][j]),dp[i][j]=max(dp[i][j],dp[i-1][j]+a[i][j]); if(j>1)dp[i][j]=max(dp[i][j],dp[i][j-1]),dp[i][j]=max(dp[i][j],dp[i][j-1]+a[i][j]); } printf("%d\n",dp[n][m]); } } const LL inf=1e18; namespace subtask2{ LL dp[N],k[N],bb[N];int A[N],B[N],id[N<<2]; LL calc(int id,int x){return (LL)k[id]*x+bb[id];} void change(int rt,int l,int r,int d){ if(!id[rt]){id[rt]=d;return;} int mid=(l+r)>>1; if(calc(d,mid)>calc(id[rt],mid))swap(id[rt],d); if(l==r)return; if(k[d]<k[id[rt]])change(rt<<1,l,mid,d); else change(rt<<1|1,mid+1,r,d); } LL query(int rt,int l,int r,int p){ if(!id[rt])return -inf; int mid=(l+r)>>1;LL res=calc(id[rt],p); if(l!=r){ if(p<=mid)res=max(res,query(rt<<1,l,mid,p)); else res=max(res,query(rt<<1|1,mid+1,r,p)); } return res; } void solve(){ if(n==1){ n=m; for(int i=1;i<=n;i++)A[i]=a[1][i],B[i]=b[1][i]; }else{ for(int i=1;i<=n;i++)A[i]=a[i][1],B[i]=b[i][1]; } dp[1]=A[1]; for(int i=1;i<=n;i++){ if(i!=1)dp[i]=max(query(1,1,n,i)+A[i],(LL)A[i]); k[i]=B[i];bb[i]=dp[i]-(LL)i*B[i]; change(1,1,n,i); } printf("%lld\n",dp[n]); } } namespace subtask3{ const int S=1.5e7+5; LL k[N],bb[N];int id[S],ls[S],rs[S],tot; LL calc(int id,int x){return (LL)k[id]*x+bb[id];} struct seg{ void change(int rt,int l,int r,int d){ if(!id[rt]){id[rt]=d;return;} int mid=(l+r)>>1; if(calc(d,mid)>calc(id[rt],mid))swap(id[rt],d); if(l==r)return; if(k[d]<k[id[rt]])change(!ls[rt]?ls[rt]=++tot:ls[rt],l,mid,d); else change(!rs[rt]?rs[rt]=++tot:rs[rt],mid+1,r,d); } LL query(int rt,int l,int r,int p){ if(!rt||!id[rt])return -inf; int mid=(l+r)>>1;LL res=calc(id[rt],p); if(l!=r){ if(p<=mid)res=max(res,query(ls[rt],l,mid,p)); else res=max(res,query(rs[rt],mid+1,r,p)); } return res; } }t[355]; int dfn,Root[355]; vector<int>A[N],B[N]; vector<LL>dp[N]; void solve(){ if(n>m){ swap(n,m); for(int i=1;i<=n;i++)A[i].resize(m+1),B[i].resize(m+1); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)A[i][j]=a[j][i],B[i][j]=b[j][i]; }else{ for(int i=1;i<=n;i++)A[i].resize(m+1),B[i].resize(m+1); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)A[i][j]=a[i][j],B[i][j]=b[i][j]; } for(int i=1;i<=n;i++)dp[i].resize(m+1); dp[1][1]=A[1][1];tot=n; for(int i=1;i<=n;i++)Root[i]=i; for(int i=1;i<=m;i++)for(int j=1;j<=n;j++){ if(i!=1||j!=1){ dp[j][i]=A[j][i]; for(int trsid=1;trsid<=j;trsid++){ dp[j][i]=max(dp[j][i],t[trsid].query(Root[trsid],1,n,j-trsid+i)+A[j][i]); } } k[++dfn]=B[j][i];bb[dfn]=dp[j][i]-(LL)i*B[j][i]; t[j].change(Root[j],1,n,dfn); } printf("%lld\n",dp[n][m]); } } int main(){ scanf("%d%d",&n,&m); if(n<=30&&m<=30)force::solve(); else{ init(); if(subtask1::check())subtask1::solve(); else if(min(n,m)==1)subtask2::solve(); else subtask3::solve(); } return 0; }
100分代码待补...