少女觉(A.c/cpp/pas/in/out)
Time Limit:1s Memory Limit:256MB
【题目大意】
在幽暗的地灵殿中,居住着一位少女,名为古明地觉。
据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力——读心。
掌控人心者,可控天下。
咳咳。
人的记忆可以被描述为一个黑块(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%的数据,n<=15
对于20%的数据,n<=500
另有30%的数据,K=1
另有30%的数据,K<=50
对于100%的数据,N<=10^5,序列长度不超过10^9
保证对于全部测试点,输入文件行数不超过2.5*10^6
贪心题
细节较多(不怎么多,主要是我zz),思路好想
总体的ratio和局部的ratio是一样的,从左往右每找到比例等于ratio就贪心取即可..
判断ratio是否相等约个分判断即可,具体实现见代码
细节①:总ratio的分母为0
解决方法:特判一下即可(样例中就可以发现)
细节②:中间某种颜色数目为0却记录在答案中
解决方法:见代码②
细节③:在记录前数目就已经大于需要的数目
如这个数据:
1
6
1 B
1 B
1 B
1 W
1 B
1 W
解决方法:见代码③
代码如下:
#include<ctype.h>
#include<cstdio>
#define N 100020
using namespace std;
inline int read(){
int x=0;char c;
do {c=getchar();} while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x;
}
char c;
int T,n,cnt0,cnt1,ans,sum;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
struct Seq{
int k,t;
inline void init(){k=t=0;}
}s[N];
struct Data{
int x,y;
Data(int _=0,int __=0):x(_),y(__){};
inline void init(){x=y=0;}
inline void trans(){
int t=gcd(x,y);
x=x/t;y=y/t;
}
}rat;
inline void init(){
sum=ans=cnt0=cnt1=0;
rat.init();
for(int i=1;i<=n;i++) s[i].init();
}
main(){
T=read();
while(T--){
init();
n=read();
for(int i=1;i<=n;i++){
s[i].k=read();
sum+=s[i].k;
do c=getchar(); while(!isalpha(c));
if(c=='B'){
s[i].t=0;
cnt0+=s[i].k;
}
else{
s[i].t=1;
cnt1+=s[i].k;
}
}
if(!cnt0 || !cnt1){//特判,只有一种颜色
printf("%d\n",sum);
continue;
}
rat=Data(cnt0,cnt1);rat.trans();//约分
cnt0=0;cnt1=0;
for(int i=1;i<=n;i++){
if(!s[i].t){
if(cnt1/*②*/ && cnt1%rat.y==0 && cnt1/rat.y*rat.x<=cnt0+s[i].k && /*③*/cnt0<=cnt1/rat.y*rat.x/*③*/){
//要满足让cnt1个黑色与白色的比为ratio,需要t=cnt1/rat.y*rat.x个白块,已经有了cnt0个,这个区间有s[i].k个,如果加上这s[i].k个数量大于t的话才说明能组成一个区间
cnt0=s[i].k+cnt0-cnt1/rat.y*rat.x;cnt1=0;
ans++;
}
else cnt0+=s[i].k;
}
else{
if(cnt0 && cnt0%rat.x==0 && cnt0/rat.x*rat.y<=cnt1+s[i].k && cnt1<=cnt0/rat.x*rat.y){
cnt1=s[i].k+cnt1-cnt0/rat.x*rat.y;cnt0=0;
ans++;
}
else cnt1+=s[i].k;
}
}
printf("%d\n",ans);
}
return 0;
}