A
找一个除去开头外的最长连续(P)段即可。
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int n;
char s[100100];
int main()
{
int T=read();
while (T--)
{
n=read();
scanf("%s",s+1);s[++n]='A';
int ans=0,lst=0;
rep(i,1,n)
{
if (s[i]=='A')
{
if (lst) ans=max(ans,i-lst-1);
lst=i;
}
}
printf("%d
",ans);
}
return 0;
}
B
枚举前两个串,第三个串是什么就确定下来了,直接用map查即可。
(貌似这么写有点卡常)
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int n,m,num[500],sum=0;
string s[2020];
map<string,int> mp;
bool diff(string a,string b)
{
rep(i,0,m-1)
if (a[i]==b[i]) return 0;
return 1;
}
int main()
{
n=read();m=read();
sum='S'+'E'+'T';
rep(i,1,n) {cin >> s[i];mp[s[i]]++;}
int ans=0;
rep(i,1,n)
{
rep(j,i+1,n)
{
string a="";
rep(k,0,m-1)
{
if (s[i][k]==s[j][k]) a=a+s[i][k];
else a+=(sum-s[i][k]-s[j][k]);
}
if (mp.count(a)) ans+=mp[a];
}
}
cout << ans/3;
return 0;
}
C
想了一万年咋贪心,最后发现dp就完事了。
记(f_{i,j,0/1})表示前(i)个数中使用了(j)个奇数,第(i)是偶数/奇数时的最大complexity. 直接转移即可。
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
namespace My_Math{
#define N 100000
int fac[N+100],invfac[N+100];
int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
int mul(int x,int y) {return 1ll*x*y%maxd;}
ll qpow(ll x,int y)
{
ll ans=1;
while (y)
{
if (y&1) ans=mul(ans,x);
x=mul(x,x);y>>=1;
}
return ans;
}
int getinv(int x) {return qpow(x,maxd-2);}
int C(int n,int m)
{
if ((n<m) || (n<0) || (m<0)) return 0;
return mul(mul(fac[n],invfac[m]),invfac[n-m]);
}
void math_init()
{
fac[0]=invfac[0]=1;
rep(i,1,N) fac[i]=mul(fac[i-1],i);
invfac[N]=getinv(fac[N]);
per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
}
#undef N
}
using namespace My_Math;
int n,a[110],f[110][110][2];
int main()
{
n=read();
rep(i,1,n) a[i]=read();
memset(f,0x3f,sizeof(f));
f[0][0][0]=f[0][0][1]=0;
rep(i,1,n) rep(j,0,i)
{
if ((j) && ((a[i]&1) || (!a[i])))
{
f[i][j][1]=min(f[i][j][1],min(f[i-1][j-1][0]+1,f[i-1][j-1][1]));
}
if ((!(a[i]&1)) || (!a[i]))
{
f[i][j][0]=min(f[i][j][0],min(f[i-1][j][0],f[i-1][j][1]+1));
}
}
int ans=min(f[n][(n+1)>>1][0],f[n][(n+1)>>1][1]);
printf("%d",ans);
return 0;
}
D
无解的情况比较显然:当子树(i)中的点的个数(<c_i)时无解。
接下来将通过构造指出存在一种所用值为([1,n])的排列的构造方法。
dfs整棵树,对当前点(u)找到排列([1,n])中尚未使用的第(c_u+1)小的数,并将其赋给点(u). 之后再遍历它的子树。这样的话就能保住前(c_u)个数正好分配给(u)的子树中比(u)上数小的点。
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
namespace My_Math{
#define N 100000
int fac[N+100],invfac[N+100];
int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
int mul(int x,int y) {return 1ll*x*y%maxd;}
ll qpow(ll x,int y)
{
ll ans=1;
while (y)
{
if (y&1) ans=mul(ans,x);
x=mul(x,x);y>>=1;
}
return ans;
}
int getinv(int x) {return qpow(x,maxd-2);}
int C(int n,int m)
{
if ((n<m) || (n<0) || (m<0)) return 0;
return mul(mul(fac[n],invfac[m]),invfac[n-m]);
}
void math_init()
{
fac[0]=invfac[0]=1;
rep(i,1,N) fac[i]=mul(fac[i-1],i);
invfac[N]=getinv(fac[N]);
per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
}
#undef N
}
using namespace My_Math;
struct node{int to,nxt;}sq[4040];
int all=0,head[2020];
int siz[2020],n,a[2020],ans[2020];
bool vis[2020];
void addedge(int u,int v)
{
all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;
}
void dfs(int u)
{
int cnt=0;
rep(i,1,n)
{
if (vis[i]) continue;
if (cnt==a[u])
{
vis[i]=1;ans[u]=i;break;
}
else cnt++;
}
siz[u]=1;
go(u,i)
{
dfs(v);siz[u]+=siz[v];
}
if (a[u]>siz[u]-1) {puts("NO");exit(0);}
}
int main()
{
n=read();int rt;
rep(i,1,n)
{
int fa=read();a[i]=read();
if (!fa) rt=i;
else addedge(fa,i);
}
dfs(rt);
puts("YES");
rep(i,1,n) printf("%d ",ans[i]);
return 0;
}
E1&E2
先考虑E1:询问([1,n])与([1,n-1]),其中([1,n])多出来的那些串就是([i,n])(只不过每个串中的字符被打乱顺序),根据([i,n])与([i+1,n])的差异就可以推出来第(i)个字符是什么,进而得到整个串。
再考虑E2:仿照E1我们可以得到([1,lfloor n/2 floor]), 之后再询问一次([1,n]). 接下来的想法比较巧妙:记(f_{i,x})为所有长度为(i)的子串中字符(x)的出现次数,那么(f_{i+1,x}-f_{i,x})就是([i+1,n-i])中字符(x)的出现次数(手画一下就是有一个前缀和一个后缀的位置没法增加,其余的位置都能多出现一次),倒推就可以得到后半部分了。
代码只放E2的,E1的被包含在里面了。
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
bool cmp(string a,string b) {return (int)a.size()>(int)b.size();}
int n,ans[110],cnt[30],f[110][26];
multiset<string> word;
string s,str[110];
void ask(int l,int r)
{
printf("? %d %d
",l,r);fflush(stdout);
}
void answer()
{
printf("! ");
rep(i,1,n) putchar(ans[i]+'a');fflush(stdout);
}
void solve1(int n)
{
if (n==1)
{
ask(1,1);
cin >> s;ans[1]=s[0]-'a';
return;
}
ask(1,n);
rep(i,1,n*(n+1)/2)
{
cin >> s;
sort(s.begin(),s.end());
word.insert(s);
}
multiset<string>::iterator it;
ask(1,n-1);
rep(i,1,n*(n-1)/2)
{
cin >> s;
sort(s.begin(),s.end());
it=word.find(s);
word.erase(it);
}
it=word.begin();
rep(i,1,n)
{
str[i]=*it;it++;
}
sort(str+1,str+1+n,cmp);
multiset<string>::iterator pre,now;
pre=word.begin();now=pre;now++;
rep(i,1,n-1)
{
string s1=str[i],s2=str[i+1];
int len=s1.size();
rep(i,0,25) cnt[i]=0;
rep(i,0,len-1) cnt[s1[i]-'a']++;
rep(i,0,len-2) cnt[s2[i]-'a']--;
rep(i,0,25)
{
if (cnt[i])
{
ans[n-len+1]=i;break;
}
}
pre=now;
}
ans[n]=str[n][0]-'a';
}
void solve2()
{
ask(1,n);
rep(i,1,(n+1)*n/2)
{
cin >> s;
int len=s.size();
rep(j,0,len-1) f[len][s[j]-'a']++;
}
per(i,(n-1)>>1,0)
{
int l=i+1,r=n-i;
rep(j,0,25) cnt[j]=0;
rep(j,l,r-1) cnt[ans[j]]++;
rep(j,0,25)
if (f[i+1][j]-f[i][j]>cnt[j]) {ans[r]=j;break;}
}
}
int main()
{
n=read();
if (n==1)
{
ask(1,1);
cin >> s;
printf("! ");cout << s;fflush(stdout);
return 0;
}
solve1(n/2);
solve2();
answer();
return 0;
}
F
首先可能发生第一次碰撞的只可能是相邻两个点,否则在这个过程中一定出现了一个点“越过”另一个点从而再发生一次相撞。
于是我们可以把所有可能作为第一次碰撞的碰撞事件存下来,再按照时间排序,考虑每个事件作为答案的概率乘一乘就好了。
按时间排序后第(i)个碰撞发生的概率=前(i-1)个碰撞不发生的概率-前(i)个碰撞不发生的概率。求前(i)个不发生的概率可以用dp解决,记(f_{i,0/1})表示第(i)个点向左/右走时所求的概率。由于一些碰撞不能发生,于是要特判一些位置无法转移。
单次dp是(O(n))的,优化的话可以把dp写成矩阵的形式,之后用线段树维护即可。(f_{i,0/1,0/1})表示当前区间([l,r])中,(l)和(r)为各个方向时的概率。再记录一下相邻位置的两个状态是否合法即可。
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000+100;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
namespace My_Math{
#define N 100000
int fac[N+100],invfac[N+100];
int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
int mul(int x,int y) {return 1ll*x*y%maxd;}
ll qpow(ll x,int y)
{
ll ans=1;
while (y)
{
if (y&1) ans=mul(ans,x);
x=mul(x,x);y>>=1;
}
return ans;
}
int getinv(int x) {return qpow(x,maxd-2);}
int C(int n,int m)
{
if ((n<m) || (n<0) || (m<0)) return 0;
return mul(mul(fac[n],invfac[m]),invfac[n-m]);
}
void math_init()
{
fac[0]=invfac[0]=1;
rep(i,1,N) fac[i]=mul(fac[i-1],i);
invfac[N]=getinv(fac[N]);
per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
}
#undef N
}
using namespace My_Math;
int n,x[N],v[N],tot=0,ban[N][2][2],p[N][2];
struct enode{int dis,v,op,id;}eve[N<<2];
bool operator <(enode p,enode q) {return 1ll*p.dis*q.v<1ll*q.dis*p.v;}
struct Matrix{
int x[2][2];
void init() {x[0][0]=x[1][0]=x[0][1]=x[1][1]=0;}
};
namespace Segment_Tree{
Matrix seg[N<<2];
Matrix pushup(Matrix a,Matrix b,int p)
{
Matrix c;c.init();
rep(i,0,1) rep(j,0,1)
{
c.x[i][j]=0;
rep(p1,0,1) rep(p2,0,1)
if (!ban[p][p1][p2])
c.x[i][j]=add(c.x[i][j],mul(a.x[i][p1],b.x[p2][j]));
}
return c;
}
void build(int id,int l,int r)
{
if (l==r)
{
seg[id].x[0][0]=p[l][0];
seg[id].x[1][1]=p[l][1];
return;
}
int mid=(l+r)>>1;
build(id<<1,l,mid);build(id<<1|1,mid+1,r);
seg[id]=pushup(seg[id<<1],seg[id<<1|1],mid);
}
void modify(int id,int l,int r,int pos)
{
if (l==r) return;
int mid=(l+r)>>1;
if (pos<=mid) modify(id<<1,l,mid,pos);
else modify(id<<1|1,mid+1,r,pos);
seg[id]=pushup(seg[id<<1],seg[id<<1|1],mid);
}
}
using namespace Segment_Tree;
int main()
{
n=read();
int inv100=getinv(100);
rep(i,1,n)
{
x[i]=read();v[i]=read();
int np=read();
p[i][1]=mul(np,inv100);p[i][0]=dec(1,p[i][1]);
}
//rep(i,1,n) cout << p[i][0] << " " << p[i][1] << endl;
rep(i,1,n-1)
{
eve[++tot]=(enode){x[i+1]-x[i],v[i+1]+v[i],1,i};
if (v[i+1]>v[i]) eve[++tot]=(enode){x[i+1]-x[i],v[i+1]-v[i],2,i};
if (v[i]>v[i+1]) eve[++tot]=(enode){x[i+1]-x[i],v[i]-v[i+1],3,i};
}
sort(eve+1,eve+1+tot);
//rep(i,1,tot) printf("%d %d %d %d
",eve[i].dis,eve[i].v,eve[i].id,eve[i].op);
build(1,1,n);
int ans=0,lstp=1;
rep(i,1,tot)
{
int id=eve[i].id,op=eve[i].op;
if (op==1) ban[id][1][0]=1;
else if (op==2) ban[id][0][0]=1;
else if (op==3) ban[id][1][1]=1;
modify(1,1,n,id);
int nowp=0,tim=mul(eve[i].dis,getinv(eve[i].v));
//cout << tim << endl;
rep(j,0,1) rep(k,0,1) nowp=add(nowp,seg[1].x[j][k]);
int p=dec(lstp,nowp);
ans=add(ans,mul(p,tim));
lstp=nowp;
}
printf("%d",ans);
return 0;
}
G
考虑增加一个字符(S_i)时答案的变化,不难发现产生贡献就是当前字符串的( m{border}).
考虑在增加了第(i)个字符时( m{border})集合的变化,对( m{border})集合中的元素(x),若(S_{x+1} eq S_i)那么(x)就将从集合中移除;如果(S_1=S_i),那么(1)就会加入到( m{border})集合中。
其实我们很容易知道了当前( m{border})集合中的元素,就是kmp中的(nxt[i-1],nxt[nxt[i-1]],cdots,)集合元素的加入很好维护,对于删除操作,对当前的( m{border})集合维护第一个下一个字符不是(S_i)的位置,之后暴力向上走同时删除贡献即可,每次删除的权值可以直接用线段树维护。由于只会有(O(n))个插入,所以暴力删除是没有问题的。
接下来就要考虑(w_i)了,也就是当前所有的权值需要对(w_i)取(min),我们可以用(mathrm{map})维护当前答案中每个权值的出现次数,之后每次暴力的找比(w_i)大的并修改,由于每个新增加的值至多只会被一次取(min)操作涉及到,所以复杂度也是正确的。
注意最后的答案有可能会爆long long,所以需要手写一个int128.
代码写的有点丑
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=600000+100;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
#define mask (1<<30)-1
const ll bas=1e18;
map<int,int> mp;
int n,jmp[N],nxt[N],str[N];
char s[N];
map<int,int>::iterator it,it2;
inline int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
namespace My_Math{
#define N 100000
int fac[N+100],invfac[N+100];
int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
int mul(int x,int y) {return 1ll*x*y%maxd;}
ll qpow(ll x,int y)
{
ll ans=1;
while (y)
{
if (y&1) ans=mul(ans,x);
x=mul(x,x);y>>=1;
}
return ans;
}
int getinv(int x) {return qpow(x,maxd-2);}
int C(int n,int m)
{
if ((n<m) || (n<0) || (m<0)) return 0;
return mul(mul(fac[n],invfac[m]),invfac[n-m]);
}
void math_init()
{
fac[0]=invfac[0]=1;
rep(i,1,N) fac[i]=mul(fac[i-1],i);
invfac[N]=getinv(fac[N]);
per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
}
#undef N
}
using namespace My_Math;
namespace Segment_Tree{
int seg[N<<2];
void modify(int id,int l,int r,int p,int v)
{
if (l==r) {seg[id]=v;return;}
int mid=(l+r)>>1;
if (p<=mid) modify(id<<1,l,mid,p,v);
else modify(id<<1|1,mid+1,r,p,v);
seg[id]=min(seg[id<<1],seg[id<<1|1]);
}
int query(int id,int l,int r,int ql,int qr)
{
if ((l>=ql) && (r<=qr)) return seg[id];
int mid=(l+r)>>1,ans=2e9;
if (ql<=mid) ans=min(ans,query(id<<1,l,mid,ql,qr));
if (qr>mid) ans=min(ans,query(id<<1|1,mid+1,r,ql,qr));
return ans;
}
}
using namespace Segment_Tree;
pair<ull,ull> ans;
void addans(ull val)
{
ans.fir+=val;
if (ans.fir>=bas)
{
ans.fir-=bas;ans.sec++;
}
}
void out()
{
if (ans.sec)
printf("%llu%018llu
",ans.sec,ans.fir);
else printf("%llu
",ans.fir);
}
int main()
{
n=read();
ull nans=0,ansc=0,answ=0;
scanf("%s",s);int w=read();
mp[w]++;nans+=w;ansc=w%26;answ=w;
addans(nans);out();
memset(str,-1,sizeof(str));
modify(1,1,n,1,w);str[1]=s[0]-'a';
int j=0;
rep(i,2,n)
{
scanf("%s",s);w=read();
int ch=(ansc+s[0]-'a')%26;
w^=(answ&mask);str[i]=ch;
modify(1,1,n,i,w);
while ((j) && (str[j+1]!=str[i])) j=nxt[j];
if (str[j+1]==str[i]) j++;nxt[i]=j;
if (str[i]==str[1])
{
nans+=w;mp[w]++;
}
if (str[nxt[i-1]+1]!=str[i]) jmp[i-1]=nxt[i-1];
else jmp[i-1]=jmp[nxt[i-1]];
int k=nxt[i-1];
while (k)
{
if (str[k+1]!=str[i])
{
int val=query(1,1,n,i-k,i-1);
mp[val]--;nans-=val;
k=nxt[k];
}
else k=jmp[k];
}
for (it=mp.upper_bound(w);it!=mp.end();)
{
mp[w]+=it->sec;
nans-=1ull*(it->fir-w)*it->sec;
it->sec=0;it2=it;it++;
mp.erase(it2);
}
addans(nans);
ansc=(ansc+nans)%26;
answ=(answ+nans)&mask;
out();
}
return 0;
}