链接:http://codeforces.com/contest/1086/problem/D
题意:
给你一个n长度的SRP组成的字符串,分别代表石头剪刀布,每次随机选取相邻的两个人进行对决,失败的一方退出队伍,相同则随机取一人退出,n-1次操作后剩下的那个人胜利。现在有q个询问,要你输出q+1个数字,每次询问会给你一个修改pos C,代表pos位置上的这个要修改成出C这个字母,输出的数字代表这样的情况下有几个人有可能会胜出,注意,修改是动态的,即字符串会随着这个人的修改而改变。
说实话一开始是真的想不太到做法,看到是cf中2700+的题目就有点怕,没怎么过多想就看了题解,然后发现这道题其实挺简单的...只是自己吓自己...咳咳
做法:
我们这里先讨论最复杂的,也就是石头剪刀布都出现了的情况,我们可以统计石头剪刀布胜利的人分别有多少,假设我们现在要统计石头胜的人有多少,那么,我们先找出第一个剪刀的位置l和最后一个剪刀的位置r,对于i位置上的石头,如果l<i<r,那么这个i就有可能获胜,为什么呢,因为假设有布在石头周边,那么它一定有机会会和i左边和右边的剪刀碰面,即最后和石头碰上的可能是两边的剪刀,那么石头就会获胜,如果是石头的话因为随机胜利所以这个i石头也可能会胜利。如果还不能明白的话,那么我们就假设我们已经对字符串做了处理,相同的一长段都并在一起,那么我们得到的关于第i个石头附近的字符串会是 ...SRS..或者...SRPS..等,那么这个是有可能先和S一起,然后被这个石头处理掉的。如果i<l,那么我们就要看看这个i左边是否存在布,为什么呢,因为如果存在的话,缩减的字符串就会是..PRS...这种类型的,很明显(手模一下都知道),这种情况下的石头是不可能胜利的,右边也以此类推。
所以对于最复杂的情况,我们有了分析,只有两种或者是一种的,都可以直接判断就好。
这样的数据结构的利用就很神奇了,还是不容易想到啊,不愧是2700+的题。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200050;
//0->剪刀 S,1->石头 R,2->布 P
int sum[3][maxn+10],po,q,aim[maxn];
set<int> pos[3];
set<int>::iterator it;
int n,aga[3][2]={{2,1},{0,2},{1,0}};
//aga中 0为小于它 1为大于它
char s[maxn],tmp[5];
int lowbit(int x){
return x&(-x);
}
int query(int x,int sum[]){
int ans=0;
while(x){
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
void add(int x,int num,int sum[]){
while(x<maxn){
sum[x]+=num;
x+=lowbit(x);
}
}
int Cal(int now){
if(pos[now].size()==0) return 0;
int ruo=aga[now][0],qiang=aga[now][1],aans=0;
if(pos[ruo].size()==0){
if(pos[qiang].size()!=0) return 0;
else return pos[now].size();
}
else{
if(pos[qiang].size()==0) return pos[now].size();
int l=*pos[ruo].begin(),r=*pos[ruo].rbegin();
aans+=(query(r,sum[now])-query(l,sum[now]));
int st=*pos[qiang].begin(),en=*pos[qiang].rbegin();
int qian=min(st,l),hou=max(r,en);
aans+=query(qian,sum[now])+query(maxn,sum[now])-query(hou,sum[now]);
}
return aans;
}
int gain(char a){
if(a=='S') return 0;
else if(a=='R') return 1;
else return 2;
}
int main(){
scanf("%d%d%s",&n,&q,s+1);
for(int i=1;i<=n;i++){
aim[i]=gain(s[i]);
add(i,1,sum[aim[i]]);
pos[aim[i]].insert(i);
}
printf("%d\n",Cal(0)+Cal(1)+Cal(2));
for(int i=1;i<=q;i++){
scanf("%d%s",&po,tmp+1);
int obj=gain(tmp[1]),yuan=aim[po];
add(po,-1,sum[yuan]); pos[yuan].erase(po);
add(po,1,sum[obj]); pos[obj].insert(po);
printf("%d\n",Cal(0)+Cal(1)+Cal(2));
aim[po]=obj;
}
return 0;
}