还是好虚。
十天之前开始发烧,烧了好多天,然后就给我烧虚了。感冒,发烧,头痛牙痛腿痛。
考试也连爆了,已经滚出一机房了。
……
这次考试也挺有意思。
T1暴力都不会。
T3暴力都不会。
T2只会莫队骗分。
结果T2只想骗60的程序A了?
数据真水。
我真垃圾。
T1
暴力是个$\Theta(N^3)$傻逼暴力,然而考试的时候并没有想到。
正解单调栈+dp。
大模拟填坑也能A,还飞快……
其实挺水的。
#include<cstdio> #include<cmath> #define ll long long using namespace std; int const N=1e6+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,top=1; int h[N],stack[N]; ll C,w[N],wf[N],dp[N]; inline int _abs(int x){ return x<0?-x:x; } inline ll max(ll x,ll y){ return x>y?x:y; } inline ll min(ll x,ll y){ return x<y?x:y; } ll find(ll x,ll l,ll r){ ll a=r-l-1,b=-(w[r-1]-w[l]<<1),c=wf[r-1]-wf[l]; b-=(l?C:0)+(r!=n?C:0),c+=C*((l?h[l]:0)+(r!=n?h[r]:0)); x=min(max((ll)(double)b/(-2.0*a)+0.5,x),min(h[l],h[r])); return a*x*x+b*x+c; } signed main(){ n=read(),C=read(); for(register int i=1;i<=n;++i) w[i]=(h[i]=read())+w[i-1],wf[i]=wf[i-1]+1ll*h[i]*h[i]; h[0]=h[++n]=1e9+7; for(register int i=1;i<=n;++i){ dp[i]=(i==1||i==n)?dp[i-1]:(dp[i-1]+C*_abs(h[i]-h[i-1])); while(top^1 && h[stack[top]]<=h[i]) if(top--!=1)dp[i]=min(dp[i],dp[stack[top]]+find(h[stack[top+1]],stack[top],i)); stack[++top]=i; } printf("%lld",dp[n]); return 0; }
T2
用莫队水过的,真没啥好说的。
题目是个四维偏序,可以CDQ嵌套,也可以打个多维树状数组。
%%%skyh,%%%yxs,都是打正解的巨神。
#include<cstdio> #include<algorithm> using namespace std; int const N=202; 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; } inline int min(int x,int y){ return x<y?x:y; } inline int max(int x,int y){ return x>y?x:y; } inline int ml(int x){ return x*x-(x-1)*(x-1); } inline int dl(int x){ return (x+1)*(x+1)-x*x; } int r,c,qs,tot,cnt=1; int bl[N][N],a[N][N]; int v[N*N],bar[N*N],now; int as[100005]; struct node{ int xo,yo,xi,yi,id; }q[100005]; struct ljj{ int w,xp,yp; }sj[N*N]; int main(){ r=read(),c=read(),qs=read(); int rs=1,cs=1; for(register int i=1;i<=r;++i) for(register int j=1;j<=c;++j) sj[++tot].xp=i,sj[tot].yp=j,sj[tot].w=read(); sort(sj+1,sj+tot+1,[](ljj skyh,ljj yxs){ return skyh.w<yxs.w; }); a[sj[1].xp][sj[1].yp]=1; for(register int i=2;i<=tot;++i) a[sj[i].xp][sj[i].yp]=cnt=cnt+(sj[i].w!=sj[i-1].w); int xlit=ceil((double)c/cs),ylit=ceil((double)r/rs); for(register int i=1,xl,xr=0,ct=0;i<=xlit;++i){ xl=xr+1,xr=min(xr+cs,c); for(register int j=1,yl,yr=0;j<=ylit;++j){ yl=yr+1,yr=min(yr+rs,r),++ct; for(register int k=yl;k<=yr;++k) for(register int u=xl;u<=xr;++u) bl[k][u]=ct; } } for(register int i=1;i<=qs;++i) q[i].id=i,q[i].xo=read(),q[i].yo=read(),q[i].xi=read(),q[i].yi=read(); sort(q+1,q+qs+1,[](node skyh,node yxs){ return (bl[skyh.xo][skyh.yo]^bl[yxs.xo][yxs.yo])?(bl[skyh.xo][skyh.yo]<bl[yxs.xo][yxs.yo]):(bl[skyh.xi][skyh.yi]>bl[yxs.xi][yxs.yi]); }); int nxo(0),nyo(0),nxi(0),nyi(0),ans(0); for(register int i=1;i<=qs;++i){ int jx=min(q[i].xi,nxi)-max(q[i].xo,nxo)+1,jy=min(q[i].yi,nyi)-max(q[i].yo,nyo)+1; if(jx<=0 || jy<=0 || (nxi-nxo+1)*(nyi-nyo+1)-(jx*jy<<1)>=0){ nxo=q[i].xo,nyo=q[i].yo,nxi=q[i].xi,nyi=q[i].yi; ++now,ans=0; for(register int j=nxo;j<=nxi;++j) for(register int k=nyo;k<=nyi;++k) if(v[a[j][k]]!=now)v[a[j][k]]=now,bar[a[j][k]]=1,++ans; else ans+=ml(++bar[a[j][k]]); as[q[i].id]=ans; continue; } while(nxo<q[i].xo){ for(register int j=nyo;j<=nyi;++j){ ans-=dl(--bar[a[nxo][j]]); if(!bar[a[nxo][j]])v[a[nxo][j]]=now-1; } ++nxo; } while(nyo<q[i].yo){ for(register int j=nxo;j<=nxi;++j){ ans-=dl(--bar[a[j][nyo]]); if(!bar[a[j][nyo]])v[a[j][nyo]]=now-1; } ++nyo; } while(nxi>q[i].xi){ for(register int j=nyo;j<=nyi;++j){ ans-=dl(--bar[a[nxi][j]]); if(!bar[a[nxi][j]])v[a[nxi][j]]=now-1; } --nxi; } while(nyi>q[i].yi){ for(register int j=nxo;j<=nxi;++j){ ans-=dl(--bar[a[j][nyi]]); if(!bar[a[j][nyi]])v[a[j][nyi]]=now-1; } --nyi; } while(nxo>q[i].xo){ --nxo; for(register int j=nyo;j<=nyi;++j) if(v[a[nxo][j]]!=now)++ans,v[a[nxo][j]]=now,bar[a[nxo][j]]=1; else ans+=ml(++bar[a[nxo][j]]); } while(nyo>q[i].yo){ --nyo; for(register int j=nxo;j<=nxi;++j) if(v[a[j][nyo]]!=now)++ans,v[a[j][nyo]]=now,bar[a[j][nyo]]=1; else ans+=ml(++bar[a[j][nyo]]); } while(nxi<q[i].xi){ ++nxi; for(register int j=nyo;j<=nyi;++j) if(v[a[nxi][j]]!=now)++ans,v[a[nxi][j]]=now,bar[a[nxi][j]]=1; else ans+=ml(++bar[a[nxi][j]]); } while(nyi<q[i].yi){ ++nyi; for(register int j=nxo;j<=nxi;++j) if(v[a[j][nyi]]!=now)++ans,v[a[j][nyi]]=now,bar[a[j][nyi]]=1; else ans+=ml(++bar[a[j][nyi]]); } as[q[i].id]=ans; } for(register int i=1;i<=qs;++i)printf("%d\n",as[i]); return 0; }
T3
两个直径分别为$l_1$和$l_2$的联通块合并后直径最小为$max(\lceil\frac{l_1}{2}\rceil+\lceil\frac{l_2}{2}\rceil+1,max(l_1,l_2))$
知道这个结论就很好做了。
先找出原树的直径,求出每个点对于直径两端点所形成子树的直径大小。
然后枚举边,$\Theta(1)$求出合并后最小的直径大小,更新答案。
对于连边方案,如果ans与原树直径相等直接断开重连。
否则连接两个联通块直径的中点即可。
#include<cstdio> #include<cstring> using namespace std; int const N=3e5+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; } inline int max(int x,int y){ return x>y?x:y; } int n,mp=-1,st,ed,ans=1e9+7,kx,ms,ct=0; int head[N],Next[N<<1],to[N<<1],t=1; int q[N],qj[N]; int pre[N]; char vis[N<<1]; int stl[N],edl[N]; inline void add(int x,int y){ to[++t]=y; Next[t]=head[x],head[x]=t; return ; } void dfs(int x,int y,int ds){ if(ds>mp)mp=ds,st=x; ++ds; for(int i=head[x];i;i=Next[i]) if(to[i]^y && i^ct && i^1^ct)dfs(to[i],x,ds); return ; } int bfs(int x){ memset(pre,0,sizeof(pre)); int u(0),v(1); q[1]=x,pre[x]=-1; while(u^v && v^n){ x=q[++u]; for(register int i=head[x];i;i=Next[i]) if(!pre[to[i]] && i^ct && i^1^ct)pre[q[++v]=to[i]]=i^1; } return v; } int get(int x,int y,bool p){ int mad(0),mal(0); for(int i=head[x];i;i=Next[i]) if(to[i]^y){ int z=get(to[i],x,p)+1; mal=max(max(mal,(p?stl[to[i]]:edl[to[i]])),mad+z); mad=max(mad,z); } (p?stl[x]:edl[x])=mal; return mad; } inline void find(int x){ printf("\n%d %d ",to[x],to[x^1]); ct=x,mp=-1; dfs(to[x],0,0); q[ms=1]=q[bfs(st)]; for(register int i=pre[q[1]];~i;i=pre[to[i]]) q[++ms]=to[i]; printf("%d ",q[ms+1>>1]); mp=-1; dfs(to[x^1],0,0); q[ms=1]=q[bfs(st)]; for(register int i=pre[q[1]];~i;i=pre[to[i]]) q[++ms]=to[i]; printf("%d ",q[ms+1>>1]); return ; } int main(){ n=read(); for(register int i=1,ff,tt;i<n;++i)ff=read(),tt=read(),add(ff,tt),add(tt,ff); dfs(1,0,0),bfs(st); for(register int i=pre[ed=q[n]];~i;i=pre[to[i]]) vis[i]=1,++ms; get(st,0,1),get(ed,0,0); for(register int i=2;i<=t;i+=2) if(vis[i]){ int x=edl[to[i]],y=stl[to[i^1]],now=max((x+1>>1)+(y+1>>1)+1,max(x,y)); if(ans>now)ans=now,qj[kx=1]=i>>1; else if(ans==now)qj[++kx]=i>>1; } else if(vis[i^1]){ int x=stl[to[i]],y=edl[to[i^1]],now=max((x+1>>1)+(y+1>>1)+1,max(x,y)); if(ans>now)ans=now,qj[kx=1]=i>>1; else if(ans==now)qj[++kx]=i>>1; } else if(ans>ms)ans=ms,qj[kx=1]=i>>1; else if(ans==ms)qj[++kx]=i>>1; printf("%d\n%d ",ans,kx); for(register int i=1;i<=kx;++i)printf("%d ",qj[i]); find(qj[1]<<1); return 0; }