标签:Contest11256 int sum 多校 pos 回合 牛客 br 输球
C - Cheating and Stealing
Description
给出一场乒乓球赛每回合的输赢情况,总回合数为\(n(n\leq10^6)\),用\(W\)和\(L\)表示赢球和输球。在\(k\)分制中,若双方中有一方得分大于\(k\)且分差大于1分,则一小局结束,结算胜负。求在\(k\in[1,n]\)时,能够赢得的小局数目。
Solution
\(k\)分制下最多有\(n/k\)小局,那么总局数约为\(nlogn\),考虑用\(O(1)\)的复杂度求得每局的结果。
记录\(sum\),\(pos\),\(br\),前\(i\)回合中赢/输球的数目为\(sum[0/1,i]\),第\(i\)次赢/输球是在第\(pos[0/1,i]\)回合,第\(i\)回合前是平分的情况下直到第\(br[i]\)回合分差能大于1,这些数组都能\(O(n)\)求得。
那么对于从第\(t\)回合开始的一小局,我方得\(k\)分是在\(j_0=pos[0,sum[0,i-1]+k]\)回合,对方得\(k\)分是在\(j_1=pos[1,sum[1,i-1]+k]\)回合。检查先得\(k\)分的一方到达\(k\)分时,即第\(j=min(j_0,j_1)\)回合时对方的分数是否为\(k-1\),若小于\(k-1\)则该方赢下一局,否则持续比赛直到\(br[j]\)。该过程是\(O(1)\)的。
Code
//Cheating and Stealing
#include <cstdio>
const int N=1e6+10;
const int P=998244353;
int n; char s[N];
int sum[2][N],pos[2][N*2]; int br[N];
int pow_n[N];
int main()
{
scanf("%d",&n); scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
sum[0][i]=sum[0][i-1]+(s[i]=='W');
sum[1][i]=sum[1][i-1]+(s[i]=='L');
if(s[i]=='W') pos[0][sum[0][i]]=i;
if(s[i]=='L') pos[1][sum[1][i]]=i;
}
br[n+1]=br[n]=n+1; for(int i=n-1;i>=1;i--) br[i]=(s[i]==s[i+1])?i+1:br[i+2];
long long ans=0;
pow_n[0]=1; for(int i=1;i<=n;i++) pow_n[i]=1LL*pow_n[i-1]*(n+1)%P;
for(int k=1;k<=n;k++)
{
int r=0;
for(int i=1;i<=n;i++)
{
int j0=pos[0][sum[0][i-1]+k];
int j1=pos[1][sum[1][i-1]+k];
if(!j0) break;
if(!j1)
{
if(sum[1][j0]-sum[1][i-1]<k-1) i=j0,r++;
else i=br[j0],r+=(s[i]=='W');
}
else if(j0<j1)
{
if(sum[1][j0]-sum[1][i-1]<k-1) i=j0,r++;
else i=br[j0],r+=(s[i]=='W');
}
else if(j0>j1)
{
if(sum[0][j1]-sum[0][i-1]<k-1) i=j1;
else i=br[j1],r+=(s[i]=='W');
}
}
ans=(ans+1LL*r*pow_n[k-1])%P;
}
printf("%lld\n",ans);
return 0;
}
标签:Contest11256,int,sum,多校,pos,回合,牛客,br,输球 来源: https://www.cnblogs.com/VisJiao/p/15087704.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。