2021牛客暑期多校训练营#5:C-Cheating and Stealing

2021牛客暑期多校训练营#5:C-Cheating and Stealing

原题链接:https://ac.nowcoder.com/acm/contest/11256/C

题目大意

G和P两个人打乒乓,共打了 n ( 1 ≤ n ≤ 1 0 6 ) n(1\leq n\leq 10^6) n(1n106)个球,比赛结果可以用长度为 n n n的由“W”和“L”组成的字符串 S S S表示,“W”表示G赢了一球,“L”表示P赢了一球。

  1. 检查在当前 S S S中,是否存在任意前缀的 m a x ( c n t W , c n t L ) ≥ i , ∣ c n t W − c n t L ∣ ≥ 2 max(cnt_W,cnt_L)≥i,|cnt_W-cnt_L|≥2 max(cntW,cntL)i,cntWcntL2,其中 c n t W cnt_W cntW表示前缀中“W”的数量, c n t L cnt_L cntL表示前缀中“L”的数量。
  2. 如果不存在这样的前缀,则结束。
  3. 如果存在,选择最短的满足条件的前缀,若 c n t W > c n t L cnt_W>cnt_L cntW>cntL,则 f i ( S ) f_i(S) fi(S) 1 1 1,反之不变。然后删除这段前缀,回到第一步。

求对于任意 i ∑ i = 1 ∣ S ∣ f i ( S ) × ( ∣ S ∣ + 1 ) i − 1   m o d   998244353 i\sum_{i=1}^{|S|}f_i(S)\times(|S|+1)^{i-1}\bmod 998244353 ii=1Sfi(S)×(S+1)i1mod998244353

解题思路

首先我们要抓住时间复杂度,发现它只可能以 O ( n l o g n ) O(n{log}n) O(nlogn)甚至 O ( n ) O(n) O(n)的时间内完成。
根据题意,在不考虑拉分的情况,总局数 = ∑ i = 1 n n 1 + n 2 + n 3 … + n n =\sum_{i=1}^n{\dfrac{n}{1}}+{\dfrac{n}{2}}+{\dfrac{n}{3}}\ldots+{\dfrac{n}{n}} =i=1n1n+2n+3n+nn,可以看出这是一个调和级数,总局数肯定小于等于 n l o g n nlogn nlogn,为我们的枚举做了保障。
之后是找出用 O ( 1 ) O(1) O(1)判断的方法,我们用 n u m r i numr_i numri记录 { 1 , 2 , 3 … i } \{1,2,3\ldots i\} {1,2,3i}中最后一个“L”,用 n u m l i numl_i numli记录 { 1 , 2 , 3 … i } \{1,2,3\ldots i\} {1,2,3i}中最后一个“W”; p r j pr_j prj表示第j个“L”在哪, p l j pl_j plj表示第j个“W”在哪; d k d_k dk表示第k个符合 S i = = S i − 1 S_i==S_{i-1} Si==Si1的i,理解这些变量可以AC这道题。

代码如下

#include<bits/stdc++.h>
#define For(i,n,m) for(int i=n;i<=m;i++)
#define FOR(i,n,m) for(int i=n;i>=m;i--)
#define mod 998244353
using namespace std;
const int MAXN=1e6+5;
int n,numl[MAXN],numr[MAXN],pl[MAXN],pr[MAXN],d[MAXN];
char c[MAXN];

int pm(int x,int p){
	int ret=1;
	while(p){
		if(p&1)ret=1ll*ret*x%mod;
		x=1ll*x*x%mod;
		p>>=1;
	}
	return ret;
}
int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0);
	cin>>n;
	cin>>c+1;
	int u=0,v=0,last=n+1;
	For(i,1,n){
		numl[i]=numl[i-1]+(c[i]=='W');
		numr[i]=numr[i-1]+(c[i]=='L');
		if(c[i]=='W')pl[++u]=i;
		else pr[++v]=i;
	}
	d[n]=n+1;
	FOR(i,n-1,1){
		if(c[i]==c[i+1])last=i+1;
		d[i]=last;
	}
	int ans=0;
	For(k,1,n){
		int s=0,tt,sum=0;
		while(numl[s]+k<=u||numr[s]+k<=v){
			if(s>n)break;
			if(numl[s]+k>u){
				tt=pr[numr[s]+k];
				if((numr[tt]-numr[s])-(numl[tt]-numl[s])<2){
					while(abs((numr[tt]-numr[s])-(numl[tt]-numl[s]))<2){
						if(tt>n)break;
						tt=d[tt];
					}
					if(tt>n)break;
					s=tt;
					if(c[s]=='W')sum++;
				}
				else s=tt;
			}
			else if(numr[s]+k>v){
				tt=pl[numl[s]+k];
				if((numl[tt]-numl[s])-(numr[tt]-numr[s])<2){
					while(abs((numl[tt]-numl[s])-(numr[tt]-numr[s]))<2){
						if(tt>n)break;
						tt=d[tt];
					}
					if(tt>n)break;
					s=tt;
					if(c[s]=='W')sum++;
				}
				else s=tt,sum++;
			}
			else if(pl[numl[s]+k]<pr[numr[s]+k]){
				tt=pl[numl[s]+k];
				if((numl[tt]-numl[s])-(numr[tt]-numr[s])<2){
					while(abs((numl[tt]-numl[s])-(numr[tt]-numr[s]))<2){
						if(tt>n)break;
						tt=d[tt];
					}
					if(tt>n)break;
					s=tt;
					if(c[s]=='W')sum++;
				}
				else s=tt,sum++;
			}
			else{
				tt=pr[numr[s]+k];
				if((numr[tt]-numr[s])-(numl[tt]-numl[s])<2){
					while(abs((numr[tt]-numr[s])-(numl[tt]-numl[s]))<2){
						if(tt>n)break;
						tt=d[tt];
					}
					if(tt>n)break;
					s=tt;
					if(c[s]=='W')sum++;
				}
				else s=tt;
			}
		}
		ans=(ans+sum*pm(n+1,k-1)%mod)%mod;
	}
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值