NOI2015
D1T1
并查集。
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<int,int> PII; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define re(i,a,b) for(i=a;i<=b;i++) #define red(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define SF scanf #define PF printf #define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxN=100000; const int maxcnt=2*maxN; int N; struct Ta{int e,x,y;}a[maxN+100]; int cnt,bak[maxcnt+100]; int pa[maxcnt+100]; inline int findroot(int a){return pa[a]<0?a:pa[a]=findroot(pa[a]);} inline void BCJ_Union(int a,int b) { int f1=findroot(a),f2=findroot(b); if(f1==f2)return; if(pa[f1]>pa[f2])swap(f1,f2); pa[f1]=pa[f1]+pa[f2]; pa[f2]=f1; } int main() { freopen("prog.in","r",stdin); freopen("prog.out","w",stdout); int i; for(int Case=gint();Case;Case--) { N=gint(); re(i,1,N){a[i].x=gint();a[i].y=gint();a[i].e=gint();} cnt=0; re(i,1,N){bak[++cnt]=a[i].x;bak[++cnt]=a[i].y;} sort(bak+1,bak+cnt+1); cnt=unique(bak+1,bak+cnt+1)-bak-1; re(i,1,N){a[i].x=lower_bound(bak+1,bak+cnt+1,a[i].x)-bak;a[i].y=lower_bound(bak+1,bak+cnt+1,a[i].y)-bak;} re(i,1,cnt)pa[i]=-1; re(i,1,N)if(a[i].e==1)BCJ_Union(a[i].x,a[i].y); int flag=1; re(i,1,N)if(a[i].e==0 && findroot(a[i].x)==findroot(a[i].y)){flag=0;break;} if(flag)PF("YES\n");else PF("NO\n"); } return 0; }
D1T2
树链剖分+线段树。
树链剖分中,我们在求边的编号的时候,我们可以用DFS,虽然这样麻烦一点,但是可以保证同一棵子树的编号在线段树中是连续的。
但考试的时候并没有想到这一点。
然后用了LCT,打了8KB,我都不想说话了。
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<int,int> PII; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define re(i,a,b) for(i=a;i<=b;i++) #define red(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define SF scanf #define PF printf #define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxN=100000; const int maxQ=100000; struct Tnode { Tnode *fa,*son[2],*path_parent; int R,L,val,add; inline Tnode(){fa=son[0]=son[1]=path_parent=0;R=L=val=add=0;} inline void down() { if(add!=0) { if(son[0]){son[0]->val+=add;son[0]->add+=add;} if(son[1]){son[1]->val+=add;son[1]->add+=add;} add=0; } } }; int N,Q; int fa[maxN+100]; int now,first[maxN+100]; struct Tedge{int v,next;}edge[maxN+100]; int dep[maxN+100]; int jump[maxN+100][31]; Tnode *pos[maxN+100]; inline void addedge(int u,int v) { now++; edge[now].v=v; edge[now].next=first[u]; first[u]=now; } int head,tail,que[maxN+100]; int size[maxN+100],heavy[maxN+100],top[maxN+100],w[maxN+100],cnt; inline void BFS() { int i,j,u,v; dep[que[head=tail=1]=1]=1; while(head<=tail) { u=que[head++]; for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)dep[que[++tail]=v]=dep[u]+1; } re(i,1,tail) { u=que[i]; jump[u][0]=fa[u]; re(j,1,30)jump[u][j]=jump[jump[u][j-1]][j-1]; } red(j,tail,1) { u=que[j]; size[u]=1; heavy[u]=-1; for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v) { size[u]+=size[v]; if(heavy[u]==-1 || size[v]>size[heavy[u]])heavy[u]=v; } } top[1]=1; re(i,2,tail) { u=que[i]; if(heavy[fa[u]]==u) top[u]=top[fa[u]]; else top[u]=u; } mmst(w,-1); cnt=0; re(i,1,tail) { u=que[i]; if(w[u]!=-1)continue; int r=u; while(r!=-1){w[r]=++cnt;r=heavy[r];} } }; int tree[4*maxN+100]; inline void down(int root) { if(tree[root]!=0) { tree[root*2]=tree[root*2+1]=tree[root]; tree[root]=0; } } inline void update(int root,int l,int r,int x,int y,int val) { if(l>r || x>y || r<x || y<l) return; if(x<=l && r<=y){tree[root]=val;return;} down(root); int mid=(l+r)/2; update(root*2,l,mid,x,y,val); update(root*2+1,mid+1,r,x,y,val); } inline int ask(int root,int l,int r,int x) { if(l<=x && x<=r && tree[root]!=0) return tree[root]; if(x<=l && r<=x) return tree[root]; down(root); int mid=(l+r)/2; if(x<=mid) return ask(root*2,l,mid,x); else return ask(root*2+1,mid+1,r,x); } inline void Cover(int a,int b,int val) { int f1=top[a],f2=top[b]; while(f1!=f2) { if(dep[f1]<dep[f2]){swap(f1,f2);swap(a,b);} update(1,1,cnt,w[f1],w[a],val); a=fa[f1]; f1=top[a]; } if(dep[a]>dep[b])swap(a,b); update(1,1,cnt,w[a],w[b],val); } inline Tnode *findp(int x) { if(x==0) return pos[0]; x=ask(1,1,cnt,w[x]); return (x==0)?0:pos[x]; } inline void Splay_Rotate(Tnode *x,int flag) { Tnode *y=x->fa,*z=y->fa; y->son[flag^1]=x->son[flag];if(x->son[flag])x->son[flag]->fa=y; x->son[flag]=y;y->fa=x; x->path_parent=y->path_parent;y->path_parent=0; x->fa=z;if(z)z->son[(y==z->son[1])]=x; } inline void Splay(Tnode *x) { Tnode *y,*z; while(x->fa) { y=x->fa;z=y->fa; if(z)z->down();y->down();x->down(); if(!z){Splay_Rotate(x,x==y->son[0]);return;} int L=(x==y->son[0]),R=(y==z->son[0]); if(L==R){Splay_Rotate(y,L);Splay_Rotate(x,R);continue;} if(L!=R){Splay_Rotate(x,L);Splay_Rotate(x,R);continue;} } x->down(); } inline void LCT_Access(Tnode *x) { Tnode *y; for(y=0;x;y=x,x=x->path_parent) { Splay(x); if(x->son[1]){x->son[1]->fa=0;x->son[1]->path_parent=x;} x->son[1]=y; if(y){y->fa=x;y->path_parent=0;} } } inline void LCT_update(Tnode *x,int v) { LCT_Access(x); Splay(x); x->val+=v; x->add+=v; x->down(); } inline void LCT_Delete(Tnode *u,Tnode *v) { LCT_Access(u); LCT_Access(v); u->path_parent=0; } inline int swim(int x,int H) { int res=x; for(int i=0;H!=0;H/=2,i++)if(H&1)res=jump[res][i]; return res; } inline void LCT_Fen(Tnode *x,int ca) { int R,L,G; Tnode *p; if(ca==x->R)return; R=x->R; L=x->L; G=swim(R,dep[R]-dep[ca]-1); p=findp(fa[L]); LCT_Delete(x,p); pos[ca]=new Tnode; pos[ca]->path_parent=p; pos[ca]->R=ca; pos[ca]->L=L; pos[ca]->val=x->val; Cover(ca,L,ca); x->path_parent=pos[ca]; x->L=G; x->val-=dep[ca]-dep[L]+1; } inline int isblack(int x) { Tnode *p=findp(x); if(!p)return 0; LCT_Access(p); Splay(p); Tnode *t=p;t->down(); while(t->son[0]){t=t->son[0];t->down();} return t==pos[0]; } inline int findL(int x) { int i; red(i,30,0)if(jump[x][i]!=0 && !isblack(jump[x][i])) x=jump[x][i]; return x; } int main() { freopen("manager.in","r",stdin); freopen("manager.out","w",stdout); int i; N=gint(); now=-1;mmst(first,-1); re(i,2,N) { fa[i]=gint()+1; addedge(fa[i],i); } BFS(); pos[0]=new Tnode; Q=gint(); while(Q--) { char s[20];int x,ca,R,L; Tnode *p; SF("%s%d\n",s,&x);x++; switch(s[0]) { case 'i': if(isblack(x)){PF("0\n");continue;} L=findL(x); ca=fa[L]; p=findp(ca); LCT_Fen(p,ca); pos[x]=new Tnode; pos[x]->R=x;pos[x]->L=L; Cover(x,L,x); pos[x]->path_parent=findp(ca); LCT_update(pos[x],dep[x]-dep[ca]); PF("%d\n",dep[x]-dep[ca]); break; case 'u': if(!isblack(x)){PF("0\n");continue;} p=findp(x); R=p->R; L=p->L; ca=fa[L]; PF("%d\n",p->val-(dep[x]-dep[L])); LCT_update(p,-p->val); LCT_Delete(p,findp(ca)); ////////// if(x==L)continue; x=fa[x]; pos[x]=new Tnode; pos[x]->R=x;pos[x]->L=L; Cover(x,L,x); pos[x]->path_parent=findp(ca); LCT_update(pos[x],dep[x]-dep[ca]); break; } } return 0; }
D1T3
背包+状压DP。
神题。。。。。。
ppt讲得比较清晰了。
30%的做法:
集合A和集合B互质就是没有包含相同的质因数,我们将每个数分解质因数。
分解质因数求出每个数包含哪些质因子,使用二进制状态压缩,存在s[i]里,每个数看作一个物品,做一次二进制状态的背包DP。
容易得到g[j|s[i]]=(g[j|s[i]]+g[j])%Mod
这是一个背包,所以j倒序循环。
100%的做法:
注意到小于等于sqrt(N)的质因数最多只有9个,每一个数最多包含一个大于sqrt(N)的质因数。
s[i]就表示i在2...sqrt(N)中包含哪些质因子,使用二进制状态压缩。
f(i)[x][y]表示可以使用前i个大质数和全部小质数,A集合包含的小质数的状态为x(二进制),B集合包含的小质数的状态为y(二进制)时的方案数。
容易得到初值f(0)[x][y]=g[x]*g[y]%Mod,其中x&y==0。
其中i这一维可以在背包中忽略。
转移时,枚举包含第i个大质数的所有整数z,他们可以某些且至少一个分配在A集合,可以某些且至少一个分配在B集合,也可以全部丢弃不用。单是绝对不可以某些分配在A集合,某些分配在B集合。
我们在做第i个大质数的时候,记d[x][y][0]表示A集合包含的小质数的状态为x(二进制),B集合包含的小质数的状态为y(二进制),包含第i个大质数的所有且至少一个整数z都分配在A集合中的方案数。
同理,d[x][y][0]表示A集合包含的小质数的状态为x(二进制),B集合包含的小质数的状态为y(二进制),包含第i个大质数的某些且至少一个整数z都分配在B集合中的方案数。
分给A:d[x|s[z]][y][0]=(d[x|s[z]][y][0]+d[x][y][0]+f[x][y])%Mod
分给B:d[x][y|s[z]][1]=(d[x][y|s[z]][1]+d[x][y][0]+f[x][y])%Mod
这是一个背包,所以x和y倒序循环。
至于为什么还要加上一个f[x][y],因为d[x][y][0]是前面用了至少一个整数z,但是有可能前面没有用整数z,用了当前的整数z,所以要加f[x][y]。
累加:f[x][y]=(f[x][y]+d[x][y][0]+d[x][y][1])%Mod
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<int,int> PII; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define re(i,a,b) for(i=a;i<=b;i++) #define red(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define SF scanf #define PF printf template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxN=500; int N; LL Mod; int flag[maxN+100]; int cnt,ge,prime[maxN+100]; int s[maxN+100]; LL g[(1<<10)+100]; LL f[(1<<9)+10][(1<<9)+10],d[(1<<9)+10][(1<<9)+10][2]; LL ans; #define wei(v,k) (((v)>>((k)-1))&1) #define two(k) (1<<(k-1)) int main() { freopen("dinner.in","r",stdin); freopen("dinner.out","w",stdout); int i,j,k; N=gint();Mod=gll(); re(i,2,N) { if(!flag[i])prime[++cnt]=i; for(j=1;j<=cnt && prime[j]*i<=N;j++) { flag[i*prime[j]]=1; if(i%prime[j]==0)break; } } if(cnt<=10) { re(i,2,N)re(j,1,cnt)if(i%prime[j]==0)s[i]|=two(j); g[0]=1; re(i,2,N)red(j,(1<<cnt)-1,0)g[j|s[i]]=(g[j|s[i]]+g[j])%Mod; ans=0; re(i,0,(1<<cnt)-1)re(j,0,(1<<cnt)-1)if((i&j)==0)ans=(ans+g[i]*g[j])%Mod; cout<<ans<<endl; } else { ge=9; re(i,2,N)re(j,1,ge)if(i%prime[j]==0)s[i]|=two(j); g[0]=1; re(i,2,N) { int t=i; re(j,1,ge)while(t%prime[j]==0)t/=prime[j]; if(t!=1)continue; red(j,(1<<ge)-1,0)g[j|s[i]]=(g[j|s[i]]+g[j])%Mod; } re(i,0,(1<<ge)-1)re(j,0,(1<<ge)-1)if((i&j)==0)f[i][j]=g[i]*g[j]%Mod; re(k,ge+1,cnt) { mmst(d,0); for(int v=prime[k];v<=N;v+=prime[k]) red(i,(1<<ge)-1,0)red(j,(1<<ge)-1,0)if((i&j)==0) { if(((i|s[v])&j)==0)d[i|s[v]][j][0]=(d[i|s[v]][j][0]+d[i][j][0]+f[i][j])%Mod; if((i&(j|s[v]))==0)d[i][j|s[v]][1]=(d[i][j|s[v]][1]+d[i][j][1]+f[i][j])%Mod; } re(i,0,(1<<ge)-1)re(j,0,(1<<ge)-1)if((i&j)==0)f[i][j]=(f[i][j]+d[i][j][0]+d[i][j][1])%Mod; } ans=0; re(i,0,(1<<ge)-1)re(j,0,(1<<ge)-1)if((i&j)==0)ans=(ans+f[i][j])%Mod; cout<<ans<<endl; } return 0; }
D2T1
多叉哈夫曼树。
如果K=2,那就是裸的哈夫曼树。现在K不是2,就是多叉哈夫曼树。
根据二叉哈夫曼树的类比,我们可以得到多叉哈夫曼树的做法:将前K小的点拿出来,然后删去,再加入一个权值等于和的点。
但是有几点地方要注意,有可能最后会剩下小于K个,这样无法取,我们在一开始的时候就补若干个0,使得个数为(K-1)的倍数+1
对于第二问,我们可以可以再排序的时候设置第二关键字,先取深度小的。
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<LL,LL> PLL; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define re(i,a,b) for(i=a;i<=b;i++) #define red(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define SF scanf #define PF printf #define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } int N,K; struct cmp{inline bool operator ()(PLL x,PLL y){return (x.fi==y.fi)?x.se>y.se:x.fi>y.fi;}}; priority_queue<PLL,vector<PLL>,cmp>Q; LL ans,cnt; int main() { freopen("epic.in","r",stdin); freopen("epic.out","w",stdout); int i; N=gint();K=gint(); re(i,1,N)Q.push(PLL(gll(),1)); while((N-1)%(K-1)!=0)Q.push(PLL(0,1)),N++; while(Q.size()!=1) { PLL t=PLL(0,0); re(i,1,K){t.fi+=Q.top().fi;upmax(t.se,Q.top().se+1);Q.pop();} ans+=t.fi; Q.push(t); } cout<<ans<<endl; cout<<Q.top().se-1<<endl; return 0; }
D2T2
后缀数组+并查集。
这种问题好像经常遇到,至少看到过2次了,后缀数组一定要熟悉啊。
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<int,int> PII; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define re(i,a,b) for(i=a;i<=b;i++) #define red(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define SF scanf #define PF printf #define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxN=300000; const LL INF=1LL<<62; int N; char S[maxN+100]; LL a[maxN+100]; int r[maxN+100],sa[maxN+100],rank[maxN+100],height[maxN+100]; int table[maxN+100],wa[maxN+100],wb[maxN+100]; inline bool cmp(int *r,int a,int b,int len){return r[a]==r[b] && r[a+len]==r[b+len];} inline void da() { int i,j,k,p,*x=wa,*y=wb,tol; re(i,1,N)r[i]=S[i]-' '+1; p=0;re(i,1,N)upmax(p,x[i]=r[i]); re(i,1,p)table[i]=0; re(i,1,N)table[x[i]]++; re(i,2,p)table[i]+=table[i-1]; red(i,N,1)sa[table[x[i]]--]=i; for(swap(x,y),x[sa[1]]=p=1,i=2;i<=N;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],0)?p:++p; for(j=1;p<N;j*=2) { tol=0; re(i,N-j+1,N)y[++tol]=i; re(i,1,N)if(sa[i]-j>=1)y[++tol]=sa[i]-j; re(i,1,p)table[i]=0; re(i,1,N)table[x[y[i]]]++; re(i,2,p)table[i]+=table[i-1]; red(i,N,1)sa[table[x[y[i]]]--]=y[i]; for(swap(x,y),x[sa[1]]=p=1,i=2;i<=N;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p:++p; } re(i,1,N)rank[sa[i]]=i; for(i=1,j,k=0;i<=N-1;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); } LL ge,As; LL ans1[maxN+100],ans2[maxN+100]; struct Tbak { int val,pos; inline Tbak(int _val=0,int _pos=0){val=_val;pos=_pos;} }bak[maxN+100];int cnt; inline bool cmpbak(Tbak a,Tbak b){return a.val>b.val;} PII route[maxN+100]; LL o[maxN+100],Q1[maxN+100],Q2[maxN+100],Q3[maxN+100],Q4[maxN+100]; /* Q1 最大非负数 Q2 最小非负数 Q3 最大非正数 Q4 最小非正数 */ int pa[maxN+100]; inline int findroot(int a){return pa[a]<0?a:pa[a]=findroot(pa[a]);} int main() { freopen("savour.in","r",stdin); freopen("savour.out","w",stdout); int i; N=gint(); scanf("%s\n",S+1); re(i,1,N)a[i]=gll(); S[++N]=' '; da(); re(i,1,N)o[rank[i]]=a[i]; re(i,1,N) { pa[i]=-1; route[i]=PII(i,i); if(o[i]>=0) Q1[i]=o[i]; else Q1[i]=-INF; if(o[i]>=0) Q2[i]=o[i]; else Q2[i]=INF; if(o[i]<=0) Q3[i]=o[i]; else Q3[i]=-INF; if(o[i]<=0) Q4[i]=o[i]; else Q4[i]=INF; } re(i,3,N)bak[++cnt]=Tbak(height[i],i); sort(bak+1,bak+cnt+1,cmpbak); int head=1; ge=0;As=-INF; red(i,N-2,0) { while(head<=cnt && bak[head].val==i) { int f1=findroot(bak[head].pos-1),f2=findroot(bak[head].pos); PII D1=route[f1],D2=route[f2]; ge+=LL(D1.se-D1.fi+1)*LL(D2.se-D2.fi+1); if(Q1[f1]!=-INF && Q1[f2]!=-INF) upmax(As,Q1[f1]*Q1[f2]); if(Q4[f1]!=INF && Q4[f2]!=INF) upmax(As,Q4[f1]*Q4[f2]); if(Q2[f1]!=INF && Q3[f2]!=-INF) upmax(As,Q2[f1]*Q3[f2]); if(Q3[f1]!=-INF && Q2[f2]!=INF) upmax(As,Q3[f1]*Q2[f2]); if(pa[f1]>pa[f2])swap(f1,f2); pa[f1]=pa[f1]+pa[f2]; pa[f2]=f1; route[f1]=PII(D1.fi,D2.se); upmax(Q1[f1],Q1[f2]); upmin(Q2[f1],Q2[f2]); upmax(Q3[f1],Q3[f2]); upmin(Q4[f1],Q4[f2]); head++; } ans1[i]=ge; ans2[i]=(ge==0)?0:As; } re(i,0,N-2)printf("%I64d %I64d\n",ans1[i],ans2[i]); return 0; }