【题解】4879. 【NOIP2016提高A组集训第11场11.9】少女觉

Description

在幽暗的地灵殿中,居住着一位少女,名为古明地觉。
据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力——读心。
掌控人心者,可控天下。
 
咳咳。
人的记忆可以被描述为一个黑块(B)与白块(W)的序列,其中情感值被定义为序列中黑块数量与白块数量之比。
小五口在发动读心术时,首先要解析人的记忆序列,因此,需要将序列分割为一些段,并且要求每一段记忆序列的情感值都相等。
下面给出两个例子:
BWWWBB -> BW + WWBB (Ratio=1:1)
WWWBBBWWWWWWWWWB -> WWWB + BBWWWWWW + WWWB (Ratio=3:1)
现在小五手上有一个人的记忆序列,她想要知道,如何将手中的记忆序列分成尽可能多的段呢?
 

Input

第一行包含一个正整数T,代表数据组数。
对于每一组测试数据,第一行包含一个正整数N。
接下来N行描述一个序列,每行包含一个正整数K和一个大写字母C,表示序列接下来有连续K个颜色为C的方块。

Output

对于每组测试数据输出一行一个正整数,表示最多分成的段数。
 

Sample Input

3
3
1 B
3 W
2 B
4
3 W
3 B
9 W
1 B
2
2 W
3 W

Sample Output

2
3
5
 

Data Constraint

对于10%的数据,n<=15
对于20%的数据,n<=500
另有30%的数据,K=1
另有30%的数据,K<=50
对于100%的数据,N<=10^5,序列长度不超过10^9
保证对于全部测试点,输入文件行数不超过2.5*10^6

 

  这道题主要的知识点是贪心,序列长度是10e9,所以我们肯定不能暴力枚举,所以我们划分阶段,首先,特判一下只有W或者只有B的序列,直接输出,接着,我们先统计出来整个序列中的W数量和B数量,因为如果一段序列可以被划分出来的话,那段序列里的W和B的数量之比一定等于总的W和B之比,我们将每一个阶段输入的东西记在数组里(2.5*10e6可以存下),然后我们考虑如果要划分的序列最多,那么我们一定是见到可以划分的序列就立即划分,所以我们可以枚举每次输入,然后判断这次输入后这段区间有没有可能断开,如果有ans++。我们为了判断这段区间内某个位置是否满足断开条件,我们看几个等式,首先设w为到目前为止有多少w,b为到目前为止有多少b,sw,sb表示总共有多少w,多少b,我们确保每一段都有:w/b=sw/sb      b/w=sb/sw  我们移项后可以发现,在每个阶段中:b=w*sb/sw,w=sw/sb*b ,我们既然可以表示出来b,w,那么我们判断这次操作输入的是W还是B,如果是W那么b不变,我们使用w=sw/sb*b这个等式,如果在w到w加上这次输入加上的w的区间中,包含了sw/sb*b的值,那么就一定是答案,ans++,然后将这次操作的值累加进w中,以方便下次使用。b的操作类似。

下面上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long t,k[100015];
char ch[100015];
long long pd(long long x,long long y,long long z){
    if(x*z%y!=0) return -1;
    else return x*z/y;
}
int main(){
    freopen("silly.in","r",stdin);
    freopen("silly.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>t;
    for(int i=1;i<=t;i++){
        int n,sb=0,sw=0;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>k[i]>>ch[i];
            if(ch[i]=='B') sb+=k[i];
            else sw+=k[i];
        }
        if(!sb||!sw){
            cout<<sb+sw<<endl;
            continue;
        }
        long long b=0,w=0,ans=0;
        for(int i=1;i<=n;i++){
            if(ch[i]=='B'){
                int p=pd(w,sw,sb);
                if(p>b&&p<=b+k[i]) ans++;
                b+=k[i];
            }
            if(ch[i]=='W'){
                int p=pd(b,sb,sw);
                if(p>w&&p<=w+k[i]) ans++;
                w+=k[i];
            }
        }
        cout<<ans<<endl;
    }
}

谢谢阅读

 

上一篇:MSTP+链路聚合实验


下一篇:where和having区别