【贪心】中山纪念中学暑期游Day12——少女觉

前言

哇这个坑爹题!!!考试时想不到正解,考试后知道了正解却打不对

啊啊啊啊

题目

在幽暗的地灵殿中,居住着一位少女,名为古明地觉。
据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力——读心。
掌控人心者,可控天下。
 
咳咳。
人的记忆可以被描述为一个黑块(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

【数据范围】

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

分析

参考题解:https://www.cnblogs.com/xxzh/p/9885397.html

显然每一段的比例与全部的比例是一样的(考试的时候很智障地没看出来,所以卡住了),

那么我们先把全部的比例算出来,然后考虑加入每一段是否可能存在一个位置满足与全部的比例相同,如果有的话就ans++

注意考虑整个序列都是 B 或者都是 W 的情况

考试暴搜代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;//记得开ll
const int MAXN=1e7;
int preb[MAXN+5],prew[MAXN+5]; 
int t,n,k,cnt1,cnt2,tot,ans;
char c;
bool flag=true;
int gcd(int a,int b)
{
	if(b==0)
		return a;
	return gcd(b,a%b);
}
void dfs(int id,int lid,int b,int w,int cnt)//lid:last id
{
	if(id>=tot)
		return ;	
	int xb=preb[id]-preb[lid];
	int xw=prew[id]-prew[lid];
	int yb=preb[tot]-preb[id];
	int yw=prew[tot]-prew[id];
	//printf("id:%d lid:%d b:%d w:%d cnt:%d\n",id,lid,b,w,cnt);
	//划开 
	if(xb*yw==xw*yb&&xb*w==xw*b&&yb*w==yw*b)
		ans=max(ans,cnt+2);
	dfs(id+1,id,xb/gcd(xb,xw),xw/gcd(xb,xw),cnt+1);
	//不划开
	xb=preb[tot]-preb[lid];
	xw=prew[tot]-prew[lid];
	if(xb*w==xw*b)
		ans=max(ans,cnt+1);
	dfs(id+1,lid,b,w,cnt);
}
void Init()
{
	flag=true;
	ans=cnt1=cnt2=0;
	memset(preb,0,sizeof(preb));
	memset(prew,0,sizeof(prew));
}
int main()
{
	freopen("silly.in","r",stdin);
	freopen("silly.out","w",stdout);
	scanf("%d",&t);
	while(t--)
	{
		Init();
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d %c",&k,&c);
			if(c=='B')
			{
				for(int i=cnt1+cnt2+1;i<=cnt1+cnt2+k;i++)
				{
					preb[i]=preb[i-1]+1;
					prew[i]=prew[i-1];
				}
				cnt1+=k;
			}
			else
			{
				for(int i=cnt1+cnt2+1;i<=cnt1+cnt2+k;i++)
				{
					prew[i]=prew[i-1]+1;
					preb[i]=preb[i-1];
				}
				cnt2+=k;
			}
			if(k!=1)
				flag=false;
		}
		tot=cnt1+cnt2;
		if(!cnt1||!cnt2)
		{
			printf("%d",cnt1+cnt2);
			continue;
		}
		if(flag)//k全是1:W,B间隔出现
		{
			if(cnt1==cnt2)
				printf("%d",cnt1);
			else
				printf("1");
		}
		else
		{
			dfs(1,0,0,0,0);
			printf("%d\n",ans);
		}
	}
	return 0;
}

莫名其妙WA代码

#include<cstdio>
#include<vector>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int MAXN=1e7;
int t,n,k,cnt1,cnt2;
int ans,b,w;
char c;
vector<int> a;
int Cal(int x,int a,int b)
{
	if(1LL*x*b%a!=0)
		return -1;
	return 1LL*x*b/a;
}
signed main()
{
	freopen("silly.in","r",stdin);
	freopen("silly.out","w",stdout);
	scanf("%lld",&t);
	while(t--)
	{
		ans=cnt1=cnt2=b=w=0;
		a.clear();
		scanf("%lld",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld %c",&k,&c);
			if(c=='B')
			{
				cnt1+=k;
				a.push_back(-k);
			}	
			else
			{
				cnt2+=k;
				a.push_back(k);
			}
		}
		if(!cnt1||!cnt2)
		{
			printf("%lld\n",cnt1+cnt2);
			continue;
		}
		int b=0,w=0,tmp;
		for(int i=0;i<a.size();i++)
		{
			tmp=a[i];
			if(tmp<0)//B
			{
				tmp=-tmp;
				int p=Cal(w,cnt2,cnt1);
				if(p>b&&p<=b+tmp)
					ans++;
				b+=tmp;	
			}
			else//W
			{
				int p=Cal(b,cnt1,cnt2);
				if(p>w&&p<=w+tmp)
					ans++;
				w+=tmp;
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

AC代码

#include<cstdio>
#include<vector>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int MAXN=1e7;
int t,n,k,cnt1,cnt2;
int ans,b,w;
char c;
vector<int> a;
int Cal(int x,int a,int b)
{
	if(1LL*x*b%a!=0)
		return -1;
	return 1LL*x*b/a;
}
signed main()
{
	//freopen("silly.in","r",stdin);
	//freopen("silly.out","w",stdout);
	scanf("%lld",&t);
	while(t--)
	{
		ans=cnt1=cnt2=b=w=0;
		a.clear();
		scanf("%lld",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld %c",&k,&c);
			if(c=='B')
			{
				cnt1+=k;
				a.push_back(-k);
			}	
			else
			{
				cnt2+=k;
				a.push_back(k);
			}
		}
		if(!cnt1||!cnt2)
		{
			printf("%lld\n",cnt1+cnt2);
			continue;
		}
		int b=0,w=0,tmp;
		for(int i=0;i<a.size();i++)
		{
			tmp=a[i];
			if(tmp<0)//B
			{
				tmp=-tmp;
				int p=Cal(w,cnt2,cnt1);
				if(p>b&&p<=b+tmp)
					ans++;
				b+=tmp;	
			}
			else//W
			{
				int p=Cal(b,cnt1,cnt2);
				if(p>w&&p<=w+tmp)
					ans++;
				w+=tmp;
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

番外

不是很懂为什么一加就把整个段都加上了...

求好心人解答

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值