zoukankan      html  css  js  c++  java
  • Codeforces Round #612 (Div. 1+Div. 2)

    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;
    }
    
  • 相关阅读:
    基本數據類型
    5月28号 垃圾回收机制
    5月28 基本运算符
    5月30日 循环之while循环
    5月28号 与用户交互
    5月31日 基本数据类型(列表类型 字典类型 元组)及其内置方法
    5月30号 基本数据类型(整数型 字符串类型)及其内置方法
    變量
    5月29日 学习笔记 可变不可变类型 成员运算符和身份运算符 条件 流程控制之if判断
    关于Flash CS4字体不能加粗的问题[附解决方法]
  • 原文地址:https://www.cnblogs.com/encodetalker/p/12723549.html
Copyright © 2011-2022 走看看