NOI2015网上同步赛滚粗记&题解
在家里有模板有对拍还是没到金牌线,太弱了、、
Day 1
8:30 你妹啊,题呢?
8:40 你妹啊,题呢?
8:50 看T1,我去,这不傻逼题吗?然后发现要离散化,map一下完事,去看T2。
9:10 T2感觉要写1H多,先看了会T3,感觉没啥思路,于是开始做T2。
9:15 T2也傻逼题?NOI怎么这么傻逼,都一眼题吗?
10:10 写完T2,调了一会,马上就过了大数据,爽。
10:20 这是T3做3H的节奏,不对啊。。
n<=500,这不是鼓励交表吗、、
在草稿纸上推了好久,就是推不出来啊、、
11:00 开始写暴搜
11:15 暴搜n>25根本跑不出来、、可我的目标是30啊
11:20 似乎n>15的质数不用判,直接乘3就行啦?
11:30 搜出了n<=30的情况,开始想怎么弄更多的分
12:00 还是想不出来啊、、看来要弃疗了,检查一下前两题啊
12:20 T1写炸了?似乎不读入要超时,似乎用map要超时?
12:30 发现在线判断是不对的,于是改为离线判
12:40 小数据都错?离散化写炸了、、
13:00 总算改好了,应该能过吧。。
13:10 T1、T2差不多了,继续弄T3吧。。
13:30 把T1、T2交了
13:40 T3弃疗,交表
230滚粗,当场AK的一大堆。。
滚粗的程序:
#include<cstdio> #include<algorithm> #define N 222222 using namespace std; int T,n,x,y,z,p,q,i,now,top,father[N],a[N],b[N],c[N],px[N],ux[N]; bool ff;char ch; void read(int &x){ for(ch=getchar();ch<'0';ch=getchar()); for(x=0;ch>='0';ch=getchar())x=x*10+ch-'0'; } int find(int x){ if(father[x]==x)return x; return father[x]=find(father[x]); } int go(int x){ int l=1,r=top; while(l<r){ int mid=(l+r)>>1; if(x>ux[mid])l=mid+1;else r=mid; } return l; } int main(){ freopen("prog.in","r",stdin); freopen("prog.out","w",stdout); read(T); while(T--){ now=0;top=0; read(n);ff=1; for(i=1;i<=200000;i++)father[i]=i; for(i=1;i<=n;i++){ read(a[i]);read(b[i]);read(c[i]); px[i*2-1]=a[i];px[i*2]=b[i]; } sort(px+1,px+2*n+1); for(i=1;i<=2*n;i++)if(px[i]!=px[i-1])ux[++top]=px[i]; for(i=1;i<=n;i++)if(c[i]==1){ p=go(a[i]); q=go(b[i]); p=find(p);q=find(q); father[p]=q; } for(i=1;i<=n;i++)if(!c[i]){ p=go(a[i]); q=go(b[i]); p=find(p);q=find(q); if(p==q){ff=0;break;} } if(ff)puts("YES");else puts("NO"); } fclose(stdin);fclose(stdout); return 0; }
#include<cstdio> #include<iostream> #define N 888888 using namespace std; int n,m,i,x,y,now,l,r,tot,sz,last[N],next[N],first[N],size[N],high[N],father[N],pos[N],belong[N]; char s[99],ch;bool v[N]; struct T{int sum,lazy,key,l,r;}t[N]; void read(int &x){ for(ch=getchar();ch<'0';ch=getchar()); for(x=0;ch>='0';ch=getchar())x=x*10+ch-'0'; } void ins(int x,int y){last[++tot]=y;next[tot]=first[x];first[x]=tot;} void dfs(int x){ v[x]=true;size[x]=1; for(int i=first[x];i;i=next[i]){ int y=last[i]; if(!v[y]){ high[y]=high[x]+1;father[y]=x; dfs(y);size[x]+=size[y]; } } } void dfs2(int x,int y){ int now=0; pos[x]=++sz;belong[x]=y; for(int i=first[x];i;i=next[i])if(high[last[i]]>high[x]&&size[last[i]]>size[now])now=last[i]; if(!now)return;dfs2(now,y); for(int i=first[x];i;i=next[i])if(high[last[i]]>high[x]&&last[i]!=now)dfs2(last[i],last[i]); } void pushdown(int k){ if(t[k].lazy){ t[k<<1].sum=(t[k<<1].r-t[k<<1].l+1)*t[k].key; t[k<<1|1].sum=(t[k<<1|1].r-t[k<<1|1].l+1)*t[k].key; t[k<<1].lazy=t[k<<1|1].lazy=1; t[k<<1].key=t[k<<1|1].key=t[k].key; t[k].lazy=t[k].key=0; } } void pushup(int k){t[k].sum=t[k<<1].sum+t[k<<1|1].sum;} void build(int k,int l,int r){ t[k].l=l;t[k].r=r; int mid=(l+r)>>1;if(l==r){t[k].sum=1;return;} build(k<<1,l,mid);build(k<<1|1,mid+1,r); pushup(k); } int query(int k,int x,int y){ pushdown(k); if(x<=t[k].l&&t[k].r<=y)return t[k].sum; int l=t[k].l,r=t[k].r,mid=(l+r)>>1; if(x>mid)return query(k<<1|1,x,y); else if(y<=mid)return query(k<<1,x,y); else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y); } void insert(int k,int x,int y,int key){ pushdown(k); if(x<=t[k].l&&t[k].r<=y){ t[k].sum=(t[k].r-t[k].l+1)*key; t[k].lazy=1; t[k].key=key; return; } int l=t[k].l,r=t[k].r,mid=(l+r)>>1; if(x>mid)insert(k<<1|1,x,y,key); else if(y<=mid)insert(k<<1,x,y,key); else insert(k<<1,x,mid,key),insert(k<<1|1,mid+1,y,key); pushup(k); } int main(){ freopen("manager.in","r",stdin); freopen("manager.out","w",stdout); read(n); for(i=2;i<=n;i++){ read(x); ins(x+1,i); } dfs(1); dfs2(1,1); build(1,1,n); read(m); while(m--){ scanf("%s",s);read(x);x++; if(s[0]=='i'){ now=0; for(;belong[x]!=belong[1];x=father[belong[x]]){ now+=query(1,pos[belong[x]],pos[x]); insert(1,pos[belong[x]],pos[x],0); } now+=query(1,pos[belong[x]],pos[x]); insert(1,pos[belong[x]],pos[x],0); printf("%d\n",now); }else{ l=pos[x];r=pos[x]+size[x]-1; now=size[x]-query(1,l,r); insert(1,l,r,1); printf("%d\n",now); } } fclose(stdin);fclose(stdout); return 0; }
#include<cstdio> long long ans[41]={0,0,3,9,21,63,111,333,693,1521,2577,7731,13491,40473,67833,119241,239481,718443,1340523,4021569,7494849,13356657,22271409,66814227,130266387,268286823,447212583,896472063,1684872063,5054616189,9566769789,28700309367,57402497367,103063130487}; long long n,p; int main(){ freopen("dinner.in","r",stdin); freopen("dinner.out","w",stdout); scanf("%lld%lld",&n,&p); if(n<=33)printf("%lld\n",ans[n]%p);else if(n==100)puts("3107203");else puts("0"); fclose(stdin);fclose(stdout); return 0; }
Day 2
8:30 打开题目,发现竟然没有提答
8:40 好晕啊,每道题都没有看懂、、而且每道题都20个测试点,各种奇奇怪怪的条件,不知道在想什么
8:45 感觉T1也就wi相等能做,才20分,没希望了
8:50 UOJ上说k=2是裸哈夫曼,哈夫曼是什么啊?百度了一下,发现k=2还是挺简单的
9:15 写完了k=2的情况,开始写wi相等的情况
9:25 写完了wi相等的情况,T1有60了,开始看T2
9:40 T2似乎暴力后缀数组有40分?
10:10 写抄完了T2的暴力,看了会T3,感觉不太可做,于是继续想T2
10:25 发现所有ai相等的情况似乎就是求出height[]然后黈力T1就行啦?
11:25 由于对后缀数组十分生疏,调了1H才调好,现在T2应该是60分。
11:30 感觉剩下40分太难拿了,就去看T3了。
11:35 T3连边很简单,然后做一个点权最长路?
12:00 写完点权最长路,发现左右会走来走去
12:05 试试看缩点吧,于是直接把tarjan+缩点模板复过来,然后发现就是APIO某题?
12:10 缩完了点,发现缩点似乎也不对。。
12:15 发现题读错了,缩点似乎对的,可以拿20分。。
12:20 开始构造返回路径
12:40 写完了走哪条路径,但是发现爆炸了,没办法了,看来T3我是没法做了
12:45 发现大数据第一问都错了,T3弃疗。T2问一问胡主力,他并没有写出来,我也没有听懂他的想法
12:50 看看能不能在T2 sa[] rank[] height[]数组中找规律,但没有结果
13:00 UOJ上有个好心人放了个题解,T1似乎K叉哈夫曼也是可以做的?
13:05 发现K叉会出现一点小问题,发现只要把多的补0就可以了。
开始用最快速度码T1,还好有原来代码的基础,不用改动太多
13:15 终于码完了,调了5分钟,调对了
13:20 把T2、T3交了,开始检查T1
13:25 发现T1还没试大数据,试了下发现对了
13:27 放心了,把T1交了
140滚粗,T3直接0分,一点希望都没有。。。
似乎网上同步赛评测机脑子进gin了,部分分都不算,算的话应该有个20分。。而且T2板子拉了个错的,以致于只有40分。。
滚粗的程序:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 222222 using namespace std; long long n,m,i,now,ans,root,l,r,y,dis,jian,m0,step,val[N],son[N][2],high[N]; long long merge(long long x,long long y){ if(!x||!y)return x+y; if(val[x]>val[y]||(val[x]==val[y]&&high[x]>high[y]))swap(x,y); son[x][1]=merge(son[x][1],y); swap(son[x][0],son[x][1]); return x; } int main(){ freopen("epic.in","r",stdin); freopen("epic.out","w",stdout); scanf("%lld%lld",&n,&m); m0=(n-1)%(m-1); for(i=1;i<=n;i++)scanf("%lld",&val[i]),root=merge(root,i); if(m0)for(i=1;i<=m-1-m0;i++)val[++n]=0,root=merge(root,n); step=(n-1)/(m-1);y=n; while(step--){ y++;dis=0; for(i=1;i<=m;i++){ now++; ans+=val[root]; val[y]+=val[root]; dis=max(dis,high[root]); root=merge(son[root][0],son[root][1]); } high[y]=dis+1; now--; root=merge(root,y); } printf("%lld\n%lld",ans,high[root]); fclose(stdin);fclose(stdout); return 0; }
#include<cstdio> #include<cstring> #include<algorithm> #define N 510000 #define inf 2000000000000000000 #define inf2 1000000000 using namespace std; int wa[N],wb[N],ws[N],wv[N],sa[N],rank[N],height[N],er[21],log2[N],f[N][21],ans1[N],n,t,tot,now,head; long long a[N],ans2[N],mav,lc[N],rc[N],ans[N],q[N],total; struct EG{long long key;int lcp;}eg[4010000]; char str[N]; bool cmp2(EG a,EG b){return a.lcp>b.lcp;} int cmp(int *r,int a,int b,int l){return (r[a]==r[b])&(r[a+l]==r[b+l]);} int min(int x,int y){if(x<y)return x;return y;} void DA(char *r,int *sa,int n,int m){ int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++)ws[i]=0; for(i=0;i<n;i++)ws[x[i]=r[i]]++; for(i=1;i<m;i++)ws[i]+=ws[i-1]; for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p){ for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++)if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++)wv[i]=x[y[i]]; for(i=0;i<m;i++)ws[i]=0; for(i=0;i<n;i++)ws[wv[i]]++; for(i=1;i<m;i++)ws[i]+=ws[i-1]; for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } void calheight(char *r,int *sa,int n){ int i,j,k=0; for(i=1;i<=n;i++)rank[sa[i]]=i; for(i=0;i<n;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); } void RMQ(){ int i,j;er[0]=1; for(i=1;i<20;i++)er[i]=er[i-1]*2; log2[0]=-1; for(i=1;i<=n;i++)log2[i]=(i&(i-1))?log2[i-1]:log2[i-1]+1; for(i=1;i<=n;i++)f[i][0]=height[i]; for(j=1;j<20;j++) for(i=1;i+er[j]-1<=n;i++) f[i][j]=min(f[i][j-1],f[i+er[j-1]][j-1]); } int lcp(int a,int b){ int x=rank[a],y=rank[b]; if(x>y)t=x,x=y,y=t; x++;int k=log2[y-x+1]; return min(f[x][k],f[y-er[k]+1][k]); } int main(){ freopen("savour.in","r",stdin); freopen("savour.out","w",stdout); scanf("%d",&n); scanf("%s",str); for(int i=0;i<n;i++)scanf("%lld",&a[i]); str[n]=0; DA(str,sa,n+1,128); calheight(str,sa,n); if(n>8000){ height[0]=-inf2;q[1]=1;head=1;lc[1]+=1; for(int i=2;i<=n;i++){ while(height[i]<=height[q[head]]&&head)head--; lc[i]=i-q[head]; q[++head]=i; } height[n+1]=-inf2;q[0]=n+1;q[1]=n;head=1;rc[n]=1; for(int i=n-1;i;i--){ while(height[i]<height[q[head]]&&head)head--; rc[i]=q[head]-i; q[++head]=i; } for(int i=1;i<=n;i++)ans[height[i]]+=lc[i]*rc[i]; for(int i=n-1;i>=0;i--)ans2[i]=ans2[i+1]+ans[i]; ans2[0]=(n*(n-1))/2; for(int i=0;i<n;i++)printf("%lld %lld\n",ans2[i],a[1]*a[1]); }else{ RMQ(); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) eg[++tot].key=a[i]*a[j],eg[tot].lcp=lcp(i,j); sort(eg+1,eg+tot+1,cmp2); now=1;mav=-inf; for(int i=n-1;i>=0;i--){ while(eg[now].lcp==i&&now<=tot){ mav=max(mav,eg[now].key); now++; } ans1[i]=now-1; if(mav==-inf)ans2[i]=0;else ans2[i]=mav; } for(int i=0;i<n;i++)printf("%d %lld\n",ans1[i],ans2[i]); } fclose(stdin);fclose(stdout); return 0; }
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 66666 #define M 333333 using namespace std; int n,i,j,s,head,tail,tot,tot2,x,y,time,scnt,top,S,ans,u,step,dis[N],first[N],first2[N],first3[N],next[M],next2[M],next3[M],last[M],last2[M],q[M<<4],dfn[N],low[N],stack[N],belong[N],val[N],pre[N],ste[N]; bool v[N],instack[N],vis[N]; struct EG{int x,y,z;}eg[N]; bool cmp1(EG a,EG b){return a.x<b.x||(a.x==b.x&&a.y<b.y);} bool cmp2(EG a,EG b){return a.y<b.y||(a.y==b.y&&a.x<b.x);} bool cmp3(EG a,EG b){return a.x+a.y<b.x+b.y||(a.x+a.y==b.x+b.y&&a.y<b.y);} bool cmp4(EG a,EG b){return a.y-a.x<b.y-b.x||(a.y-a.x==b.y-b.x&&a.y<b.y);} void insert(int x,int y){last[++tot]=y;next[tot]=first[x];first[x]=tot;} void ins(int x,int y){last2[++tot2]=y;next2[tot2]=first2[x];first2[x]=tot2;} void tarjan(int x){ int now=0; dfn[x]=low[x]=++time; stack[++top]=x; instack[x]=1; for(int i=first[x];i;i=next[i]){ int y=last[i]; if(!dfn[y]){tarjan(y);if(low[y]<low[x])low[x]=low[y];} else if(instack[y]&&dfn[y]<low[x])low[x]=dfn[y]; } if(low[x]==dfn[x]){ scnt++; while(now!=x){ now=stack[top--]; instack[now]=0; belong[now]=scnt; val[scnt]+=1; } } } void rebuild(){ for(i=1;i<=n;i++) for(j=first[i];j;j=next[j]) if(belong[i]!=belong[last[j]])ins(belong[i],belong[last[j]]); } void spfa(){ int head=0,tail=1;S=n; q[1]=belong[S];v[belong[S]]=1;dis[belong[S]]=val[belong[S]]; while(head!=tail) for(i=first2[x=q[++head]],v[x]=0;i;i=next2[i]) if(dis[x]+val[y=last2[i]]>dis[y]){ pre[y]=x; dis[y]=dis[x]+val[y]; if(!v[y])v[q[++tail]=y]=1; } } int main(){ freopen("farm.in","r",stdin); freopen("farm.out","w",stdout); scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d%d",&eg[i].x,&eg[i].y),eg[i].z=i; n++;eg[n].x=0;eg[n].y=0;eg[n].z=n; sort(eg+1,eg+n+1,cmp1); for(i=2;i<=n;i++)if(eg[i-1].x==eg[i].x)insert(eg[i-1].z,eg[i].z); sort(eg+1,eg+n+1,cmp2); for(i=2;i<=n;i++)if(eg[i-1].y==eg[i].y)insert(eg[i-1].z,eg[i].z),insert(eg[i].z,eg[i-1].z); sort(eg+1,eg+n+1,cmp3); for(i=2;i<=n;i++)if(eg[i-1].x+eg[i-1].y==eg[i].x+eg[i].y)insert(eg[i-1].z,eg[i].z); sort(eg+1,eg+n+1,cmp4); for(i=2;i<=n;i++)if(eg[i-1].x-eg[i-1].y==eg[i].x-eg[i].y)insert(eg[i-1].z,eg[i].z); for(i=1;i<=n;i++)if(!dfn[i])tarjan(i); rebuild(); spfa(); for(i=1;i<=n;i++)if(dis[belong[i]]>ans)ans=dis[belong[i]],u=belong[i]; printf("%d\n",ans-1); for(i=1;i<=n;i++){ next3[i]=first3[belong[i]]; first3[belong[i]]=i; } while(dis[u]>1){ for(i=first3[u];i;i=next3[i])ste[++step]=i; u=pre[u]; } for(i=step;i;i--)printf("%d ",ste[i]);puts(""); printf("%d\n",n-1); /*for(i=1;i<=n;i++)printf("%d ",belong[i]);puts(""); for(i=1;i<=n;i++)printf("%d ",pre[i]);puts(""); for(i=1;i<=n;i++)printf("%d ",dis[belong[i]]);puts("");*/ fclose(stdin);fclose(stdout); return 0; }
感觉自己实力还是太弱了,很多算法不会,傻逼题要写好久,不会的题骗不到多少分,这样不滚粗才怪呢
后记:
哎Day2T2真的是后缀树裸题,用后缀自动机建出后缀树然后后缀树上随便弄就可以了。。比后缀数组不知道高到哪里去了
Day1T3其实也很简单,做的时候非常脑残,都想到放素数了背包想不出,会背包50肯定有的啊。。。
按照题解的方法来做,感觉非常有道理,代码也很短。。是这次NOI第3短的题。。。
简要题解
Day1:
T1程序自动分析:直接并查集,遇到相等就合并不等就判断,要离散化
T2软件包管理器:可以说是裸的树剖了,有两个操作,安装操作相当于把一条链全改为1,卸载操作相当于把一个子树全改为0,然后树剖裸上就可以了
T3寿司晚宴:先考虑往A和B两边放素数,然后判断,要求每个方案的素数在选的数中至少要分解出至少一个
然后得到g[j|u[i]]=g[j|u[i]]+g[j](u[i]为i分解质因数的二进制表示),直接背包就可以了
然后发现50-100的素数不用管直接乘3就可以了,然后轻松50分。。
但发现小于根号n的素数只有9个,可以对小质数进行压缩,大质数进行DP,设初值dp[x][y]=g[x]*g[y]((x&y)==0)
然后枚举每个大质数的所有整数z,z可以分给A、B或不用,于是
#include<cstdio> #include<cmath> #include<cstring> #define N 555 long long M,n,i,j,k,l,w,tmp,now,ans,sum,p,sq,SZ,u[N],g[N],pr[N],d[N][N][2],dp[N][N]; bool f[N],y[N]; int main(){ scanf("%lld%lld",&n,&M); for(i=2;i<=n;i++){ if(!f[i])pr[++p]=i; for(j=1;j<=p&&i*pr[j]<=n;j++){ f[i*pr[j]]=1; if(i%pr[j]==0)break; } } for(i=1;i<=p;i++)if(pr[i]<=sqrt(n))++sq;SZ=(1<<sq)-1; for(i=2;i<=n;i++){ for(tmp=i,j=1;j<=sq&&tmp>1;j++) if(tmp%pr[j]==0){ u[i]|=1<<(j-1); while(tmp%pr[j]==0)tmp/=pr[j]; } if(tmp>1)y[i]=1; } for(g[0]=1,i=2;i<=n;i++) if(!y[i])for(j=SZ;j>=0;j--)g[j|u[i]]=(g[j|u[i]]+g[j])%M; for(i=0;i<=SZ;i++) for(j=0;j<=SZ;j++) if((i&j)==0)dp[i][j]=(g[i]*g[j])%M; for(i=sq+1;i<=p;i++){ memset(d,0,sizeof(d)); for(j=pr[i];j<=n;j+=pr[i]) for(k=SZ;k>=0;k--) for(l=SZ;l>=0;l--)if((k&l)==0){ d[k|u[j]][l][0]=(d[k|u[j]][l][0]+d[k][l][0]+dp[k][l])%M; d[k][l|u[j]][1]=(d[k][l|u[j]][1]+d[k][l][1]+dp[k][l])%M; } for(j=0;j<=SZ;j++) for(k=0;k<=SZ;k++) if((j&k)==0)dp[j][k]=(dp[j][k]+d[j][k][0]+d[j][k][1])%M; } for(i=0;i<=SZ;i++) for(j=0;j<=SZ;j++) if((i&j)==0)sum=(sum+dp[i][j])%M; printf("%lld",sum); }
Day2:
T1荷马史诗:就是K叉哈夫曼,每次把最小的K个选出来求和再放到堆里,如此往复即可,不过K叉时要把多的填为0才能保证正确性
T2品酒大会:后缀数组的做法暂时不会,不过这题是后缀树裸题,先后缀自动机构造出后缀树,然后在后缀树上搞,维护两个最大值和两个最小值,很明显最大值是max(max(ma1[x]*ma2[x],mi1[x]*mi2[x]),max(ma1[x]*mi2[x],ma2[x]*mi1[x])); else if(sz[x]>=3)now=max(max(ma1[x]*ma2[x],mi1[x]*mi2[x]),ma1[x]*mi1[x]),然后统计方案数,注意统计size时由于边是有权值的,要稍微处理一下,不过也非常简单,在每一层单独统计,然后去掉多余的就可以了
#include<cstdio> #include<algorithm> #include<cstring> #define N 600006 #define inf 2e18 using namespace std; long long n,m,cnt,S,last,tot,now,tmp,p,q,np,nq,c,i,j,y,son[N][26],fa[N],step[N],a[N],to[N],mi1[N],mi2[N],ma1[N],ma2[N],sz[N],la[N],ne[N],fi[N],va[N],ans[N],mav[N],nx[N]; char s[N];bool vis[N];//x,y是连的两个点,z是长度 void insert(long long x,long long y,long long z){la[++tot]=y;ne[tot]=fi[x];va[tot]=z;fi[x]=tot;} void add(long long x){//后缀自动机 c=s[x]-'a';p=last;step[np=last=++cnt]=step[p]+1;to[np]=i; for(;p&&!son[p][c];p=fa[p])son[p][c]=np; if(!p)fa[np]=S;else{ q=son[p][c]; if(step[p]+1==step[q])fa[np]=q;else{ nq=++cnt;step[nq]=step[p]+1; memcpy(son[nq],son[q],sizeof son[q]); fa[nq]=fa[q];fa[q]=fa[np]=nq; for(;p&&son[p][c]==q;p=fa[p])son[p][c]=nq; } } } void dfs(long long x,long long high){//在后缀树上遍历 if(to[x])ma1[x]=mi1[x]=a[to[x]],sz[x]=1;else ma1[x]=-inf,mi1[x]=inf,sz[x]=0; ma2[x]=-inf;mi2[x]=inf; for(long long i=fi[x];i;i=ne[i]){ long long y=la[i]; dfs(y,high+va[i]); if(ma1[y]>ma1[x]){ ma2[x]=ma1[x];ma1[x]=ma1[y]; if(ma2[y]>ma2[x])ma2[x]=ma2[y]; }else if(ma1[y]>ma2[x])ma2[x]=ma1[y]; if(mi1[y]<mi1[x]){ mi2[x]=mi1[x];mi1[x]=mi1[y]; if(mi2[y]<mi2[x])mi2[x]=mi2[y]; }else if(mi1[y]<mi2[x])mi2[x]=mi1[y]; sz[x]+=sz[y];nx[x]+=nx[y]; } now=-inf;tmp=(sz[x]*(sz[x]-1))/2; if(sz[x]>=4)now=max(max(ma1[x]*ma2[x],mi1[x]*mi2[x]),max(ma1[x]*mi2[x],ma2[x]*mi1[x])); else if(sz[x]>=3)now=max(max(ma1[x]*ma2[x],mi1[x]*mi2[x]),ma1[x]*mi1[x]); else if(sz[x]>=2)now=ma1[x]*ma2[x]; if(now!=inf)ans[high]+=tmp-nx[x],mav[high]=max(mav[high],now); nx[x]+=tmp-nx[x]; } int main(){ scanf("%lld",&n);scanf("%s",s+1); for(S=last=++cnt,i=n;i;i--)add(i);//倒着加入后缀自动机 for(vis[S]=i=1;i<=cnt;i++)//不断回退建立出后缀树 if(to[i]&&!vis[i])for(j=i;!vis[j];vis[j]=1,j=fa[j])insert(fa[j],j,step[j]-step[fa[j]]); for(i=0;i<=n;i++)mav[i]=-inf; for(i=1;i<=n;i++)scanf("%lld",&a[i]); dfs(1,0); for(i=n-1;i>=0;i--)ans[i]=ans[i]+ans[i+1],mav[i]=max(mav[i],mav[i+1]); for(i=0;i<n;i++){ if(mav[i]==-inf)mav[i]=0; printf("%lld %lld\n",ans[i],mav[i]); } }
T3小园丁与老司机:实在是太难了,蒟蒻实在不会,40分还是可以接受的,100分就太那啥了。。。
[NOI2015][BZOJ4195]程序自动分析[BZOJ4196]软件包管理器[BZOJ4198]荷马史诗【BZOJ4199】品酒大会【BZOJ4197】寿司晚宴
2015年7月19日 20:03
哈夫曼太难了QwQ
2015年7月19日 20:30
跪Au爷
2015年7月21日 16:53
其实我D2T2是写出来的