题目
在幽暗的地灵殿中,居住着一位少女,名为古明地觉。
据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力——读心。
掌控人心者,可控天下。
人的记忆可以被描述为一个黑块(B)与白块(W)的序列,其中情感值被定义为序列中黑块数量与白块数量之比。
小五口在发动读心术时,首先要解析人的记忆序列,因此,需要将序列分割为一些段,并且要求每一段记忆序列的情感值都相等。
下面给出两个例子:
BWWWBB -> BW + WWBB (Ratio=1:1)
WWWBBBWWWWWWWWWB -> WWWB + BBWWWWWW + WWWB (Ratio=3:1)
现在小五手上有一个人的记忆序列,她想要知道,如何将手中的记忆序列分成尽可能多的段呢?
输入
第一行包含一个正整数T,代表数据组数。
对于每一组测试数据,第一行包含一个正整数N。
接下来N行描述一个序列,每行包含一个正整数K和一个大写字母C,表示序列接下来有连续K个颜色为C的方块。
输出
对于每组测试数据输出一行一个正整数,表示最多分成的段数。
样例
输入 | 输出 |
---|---|
3 3 1 B 3 W 2 B 4 3 W 3 B 9 W 1 B 2 2 W 3 W |
2 3 5 |
数据范围
对于10%的数据,(Nleqslant15)
对于20%的数据,(Nleqslant500)
另有30%的数据,(K=1)
另有30%的数据,(Kleqslant50)
对于100%的数据,(Nleqslant10^5),序列长度不超过(10^9)
保证对于全部测试点,输入文件行数不超过(2.5 imes10^6)
题解
因为每一段记忆序列的情感值都相等,设为K,那么由合比性质我们很容易知道,整个序列的情感值也为K。
一旦情感值确定下来了,我们的分割就很方便了。很容易想到,遍历一遍序列,每当情感值为K时就分割,然后重新统计W和B的数量,当情感值为K时再分割,如此反复。
然而,如果我们直接扫一遍整个序列,(10^9)的长度可能会超时。
由合比性质,我们可以知道,若干分割出的小序列拼起来之后的序列的情感值也为K。那么我们就可以由当前W(B)的数量计算出要达到K我们还需要多少B(W),而再次达到K的时候,我们就可以再分割出一个小序列。
如果当前我们所遍历到的这一段,B(W)的数量可以满足在这一段的某个位置,情感值再次达到K,那么我们就可以再当前的这一段分割出一个小序列。如果计算出当前需要的不是整数个,那么说明以当前的W(B)的数量,我们无法让情感值达到K,也就无法再分割出一个小序列。
PS:此题解部分借鉴星星之火OIer的博客
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
int rnd,n;
ll cal(ll x,ll a,ll b){//用于计算还需要多少B(W)
//因为x*b可能爆int,而如果先除,因为无法确定a是哪一个的约数,有可能因为下取整而使答案错误,所以要开ll
return (x*b)%a ? -1 : x*b/a;
}
int main(){
// freopen("silly.in","r",stdin);
// freopen("silly.out","w",stdout);
scanf("%d",&rnd);
while(rnd--){
ll times[MAXN];
char ch[MAXN][2];
ll sumb=0,sumw=0;
scanf("%d",&n);
for(register int i=1;i<=n;i++){
scanf("%lld %s",×[i],&ch[i]);
if(ch[i][0]=='B') sumb+=times[i];
if(ch[i][0]=='W') sumw+=times[i];
}
if(!sumb || !sumw){//如果全是B或W,则可以分成序列长(sumb+sumw)段
printf("%d
",sumb+sumw);
continue;
}
ll cntb=0,cntw=0;
int ans=0;
for(register int i=1;i<=n;i++){
if(ch[i][0]=='B'){
ll p=cal(cntw,sumw,sumb);
if(p>cntb && p<=cntb+times[i]) ans++;
cntb+=times[i];
}
if(ch[i][0]=='W'){
ll p=cal(cntb,sumb,sumw);
if(p>cntw && p<=cntw+times[i]) ans++;
cntw+=times[i];
}
}
printf("%d
",ans);
}
return 0;
}