前言
- B组题竟然没炸,开心= =
- 主要是考完就放假心态很好。
- 然而T1打挂了233。
- 继续努力。
T1
- 正解神仙矩阵快速幂。
- 然而好像都是把周期循环周期长度次,这样可以保证正确。
- 代码很短。主要是这个题值域很小,所以最长不下降子序列的暴力复杂度$Theta(N^2)$变为了$Theta(150N)$,没必要打线段树或树状数组。
- 时间复杂度$Theta(150len^2)$,空间复杂度$Theta(len^2)$,len是周期长度的平方。
#include<bits/stdc++.h> #define ll long long using namespace std; int const N=155; ll n,ans; int t,A,B,C,D,st,lit,zc; int a[110000],vis[N],bar[N]; int main(){ scanf("%lld%d%d%d%d%d",&n,&t,&A,&B,&C,&D); const int mod=D; for(register int i=1;i<=n;++i){ if(vis[a[i]=t]){st=vis[t];lit=i-1;zc=i-vis[t];break;} vis[t]=i,t=(A*t*t+B*t+C)%mod; } if(!st)st=n+1; lit=min(n,1ll*lit+zc*zc); for(register int i=st+zc;i<=lit;++i)a[i]=a[i-zc]; for(register int i=1,z,lt;i<st;++i){ z=0,lt=a[i]; for(register int j=0;j<=lt;++j)z=max(z,bar[j]); bar[lt]=++z,ans=max(ans,1ll*z); } for(register int i=st,z,lt;i<=lit;++i){ z=0,lt=a[i]; for(register int j=0;j<=lt;++j)z=max(z,bar[j]); bar[lt]=++z,ans=max(ans,(n-i)/zc+z); } printf("%lld",ans); return 0; }
T2
- 正解神仙DP,稍不会。
- 向zzn大神学习了同余系最短路。
- 找出最小的体积,设为V。
- 那么V的倍数肯定可以凑出,我们只需考虑凑出小于V的V种情况所需要的最小体积即可。
- spfa跑最短路。注意需要满足题目中的限制。
- 时间复杂度上界$Theta(kV^2)$,但实际远远达不到这个上界。
空间复杂度$Theta(kV)$。 - 其中k是spfa的常数。
#include<cstdio> #include<algorithm> #include<cstring> #define ll long long int const N=1e4; int n,tot,m,l,c,mod=N,lit; int a[101]; ll f[N]; int lm[N]; bool v[N]; int q[10000000],t=1,u,x; template<class T> inline T read(){ T ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline int min(int x,int y){ return x<y?x:y; } int main(){ n=read<int>(),m=read<int>(); for(register int i=1;i<=n;++i)mod=min(mod,a[i]=read<int>()); const int MOD=mod; l=read<int>(),c=read<int>(); std::sort(a+1,a+n+1); for(register int i=1;i<=n;++i) if(a[i]!=a[i-1])a[++tot]=a[i]; n=tot; for(lit=1;lit<=n&&a[lit]<l;++lit);--lit; memset(f,0x3f,MOD<<3),memset(lm,0x3f,MOD<<2); f[0]=lm[0]=0; while(u^t){ v[x=q[++u]]=0; ll bs=f[x]; for(register int i=1,y,la=lm[x],lnow=la+1,lt=min(n,c==lm[x]?lit:n);i<=lt;++i){ y=(x+a[i])%MOD; if(f[y]>bs+a[i]){ f[y]=bs+a[i]; if(i>lit)lm[y]=lnow; if(!v[y])v[q[++t]=y]=1; } else if(f[y]==bs+a[i]){ if(i>lit && lm[y]>lnow){ lm[y]=lnow; if(!v[y])v[q[++t]=y]=1; continue; } else if(i<=lit && lm[y]>=lnow){ lm[y]=la; if(!v[y])v[q[++t]=y]=1; } } } } while(m--){ ll w=read<ll>(); puts(f[w%MOD]<=w?"Yes":"No"); } return 0; }
T3
- 本场考试最简单的题目竟然在T3……
- 线段树维护dfs序即可。
- 更新时向上标记。如果当前点在之前被更新过直接停止,这样保证每个点只被更新一次。
- 然后这个题就没了。
- 时间复杂度$Theta(NlogN)$,空间复杂度$Theta(N)$。
- 但考试的时候我却打了一个半小时才打完。
- 原因是我将被修改成黑点的点的父链又单独考虑了一遍,需要树链剖分+树状数组。
- 所以代码会很长……
#include<cstdio> #define L tr[k].lc #define R tr[k].rc using namespace std; int const N=1e5+5,M=2e5+5; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } int n,m; int head[N],Next[M],to[M],t; int val[N]; bool vis[N]; int l[N],r[N],tot; int siz[N],son[N],fa[N],dep[N],top[N]; int blk; struct node{ int lc,rc,w,f; }tr[N<<2]; int BIT[N]; inline void add(int x,int y){ to[++t]=y; Next[t]=head[x],head[x]=t; return ; } int dfs1(int x,int y){ for(int i=head[x],nw=0,dnow=dep[x]+1,z;i;i=Next[i]) if((z=to[i])^y){ dep[z]=dnow,fa[z]=x; siz[x]+=dfs1(z,x); if(siz[z]>nw)nw=siz[z],son[x]=z; } return ++siz[x]; } void dfs2(int x,int y){ l[x]=++tot,top[x]=y; if(!son[x]){r[x]=tot;return ;} dfs2(son[x],y); for(int i=head[x],sw=son[x],fw=fa[x];i;i=Next[i]) if(to[i]!=sw && to[i]!=fw)dfs2(to[i],to[i]); r[x]=tot; return ; } void build(int x,int y,int k){ L=x,R=y; if(x==y)return ; int mid=x+y>>1; return build(x,mid,k<<1),build(mid+1,y,k<<1|1); } inline int max(int x,int y){ return x>y?x:y; } inline void down(int k){ int lk=k<<1,rk=lk|1,z=tr[k].f; tr[k].f=0; tr[lk].w=max(z,tr[lk].w),tr[lk].f=max(z,tr[lk].f); tr[rk].w=max(z,tr[rk].w),tr[rk].f=max(z,tr[rk].f); return ; } inline int ask(int x,int k){ while(L^R){ if(tr[k].f)down(k); if(x<=(L+R>>1))k<<=1; else k=k<<1|1; } return tr[k].w; } void getmax(int x,int y,int z,int k){ tr[k].w=max(z,tr[k].w); if(L>=x&&R<=y){tr[k].f=max(z,tr[k].f);return ;} int mid=L+R>>1; if(x<=mid)getmax(x,y,z,k<<1); if(y>mid)getmax(x,y,z,k<<1|1); return ; } inline void change(int x,int y){ while(x<=n)BIT[x]+=y,x+=x&-x; return ; } inline int query(int x){ int ans=0; while(x)ans+=BIT[x],x-=x&-x; return ans; } inline void update(int x){ int fx=fa[top[x]]; while(fx)change(l[top[x]],1),change(l[x]+1,-1),x=fx,fx=fa[top[x]]; return change(1,1),change(l[x]+1,-1); } inline void modify(int x){ while(!vis[x]){ if(l[fa[x]]<l[x])getmax(l[fa[x]],l[x]-1,val[fa[x]],1); if(r[fa[x]]>r[x])getmax(r[x]+1,r[fa[x]],val[fa[x]],1); vis[x]=1,x=fa[x]; } return ; } int main(){ //freopen("lca2.in","r",stdin); //freopen("1.out","w",stdout); n=read(),m=read(); for(register int i=1;i<=n;++i)val[i]=read(); for(register int i=1,ff,tt;i<n;++i) ff=read(),tt=read(),add(ff,tt),add(tt,ff); dfs1(1,0),dfs2(1,1); build(1,n,1),vis[1]=1; while(m--){ char bb=getchar(); while(bb^'Q'&&bb^'M')bb=getchar(); int x=read(); if(bb=='Q'){ if(blk)printf("%d ",query(l[x])?max(val[x],ask(l[x],1)):ask(l[x],1)); else puts("-1"); continue; } update(x),blk=1; getmax(l[x],r[x],val[x],1); modify(x); } return 0; }