Codeforces Round #782 (Div. 2)

A. Red Versus Blue

题目链接:Problem - A - Codeforces

 样例输入:

6
3 2 1
10 6 4
11 6 5
10 9 1
10 8 2
11 9 2

样例输出:

RBR
RRBRBRBRBR
RBRBRBRBRBR
RRRRRBRRRR
RRRBRRRBRR
RRRBRRRBRRR

题意:两个队伍进行比赛,一共n场比赛,其中红队赢a场,蓝队赢b场,让我们输出一种比赛结果方案,使得任意一方连胜次数最大值最小。

分析:这个我们直接贪心求解即可,就是我们统计一下平均一方赢多少次另一方可以赢一次,一开始我们是用上取整,当一方获胜次数可以被另一方整除的时候我们直接循环输出即可。然后我们直接按照这个方法进行模拟求解即可。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n,a,b;
		scanf("%d%d%d",&n,&a,&b);
		int cnt=a/(b+1);
		int t=a%(b+1);
		for(int i=1;i<t;i++)
		{
			for(int j=1;j<=cnt+1;j++)
				printf("R"),a--;
			printf("B"),b--;
		}
		while(b--)
		{
			for(int j=1;j<=cnt;j++)
				printf("R"),a--;
			printf("B");
		}
		for(int j=1;j<=a;j++)
			printf("R");
		puts("");
	}
	return 0;
} 

B. Bit Flipping

题目链接:Problem - B - Codeforces

样例输入:

6
6 3
100001
6 4
100011
6 0
000000
6 1
111001
6 11
101100
6 12
001110

样例输出:

111110
1 0 0 2 0 0 
111110
0 1 1 1 0 1 
000000
0 0 0 0 0 0 
100110
1 0 0 0 0 0 
111111
1 2 1 3 0 4 
111110
1 1 4 2 0 4

题意:给定一个长度为n的01串,然后我们可以对这个字符串进行k次操作,每次操作选定一个字符,操作后除了这个字符以外的其他字符全部反转,求k次操作后字符串的最大字典序,还需要输出每个字符的操作次数。

分析:我们先考虑第i个字符,如果第i个字符是1,这个时候需要看一下k的奇偶性,如果k是奇数,那么我们需要操作第i个字符一次,那么这一次操作,第i个字符不会发生变化,然后剩下的操作次数为偶数,剩余的操作只要是不操作第i个字符,那么最后第i个字符一定是1.同理贪心可以得到其他的情况,如果k是偶数,那么对于第i个字符是1的情况我们就可以直接不操作这个字符,对于第i个字符是0的情况我们就可以操作这个字符一次。贪心来想我们就需要从第一个位置开始往后考虑,尽量使得每一个位置都为1,最后如果剩余操作次数就全部操作最后一个字符。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
char s[N];
int t[N];
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++) t[i]=0;
		scanf("%s",s+1);
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			if(k==cnt) break;
			if(s[i]=='1')
			{
				if(k&1)
				{
					t[i]++;
					cnt++;
				}
			}
			else
			{
				if(k%2==0)
				{
					t[i]++;
					cnt++;
				}
			}
			s[i]='1';
			if(cnt==k)
			{
				if(k&1)
					for(int j=i+1;j<=n;j++)
					{
						if(s[j]=='0') s[j]='1';
						else s[j]='0';
					}
				break;
			}
		}
		if(k!=cnt)
		{
			for(int i=cnt+1;i<=k;i++)
				t[n]++;
			if((k-cnt)&1) s[n]='0';
		}
		for(int i=1;i<=n;i++)
			printf("%c",s[i]);
		puts("");
		for(int i=1;i<=n;i++)
			printf("%d ",t[i]);
		puts("");
		
	}
	return 0;
}

C. Line Empire

题目链接:Problem - C - Codeforces

样例输入:

4
5 2 7
3 5 12 13 21
5 6 3
1 5 6 21 30
2 9 3
10 15
11 27182 31415
16 18 33 98 874 989 4848 20458 34365 38117 72030

样例输出:

173
171
75
3298918744

题意:给定n个城市的位置(位置均大于0),一开始有一个首都位于0号点,然后我们每次可以花费a⋅|c1−c2|的代价进行迁都,其中c1是当前首都位置,c2是要迁都到的位置,a是一个迁都代价系数,前提是c2这个城市已经被占领了。我们还可以花费b⋅|c1−c2|占领位于c2位置的城市,但是不改变首都的位置,而且c1和c2之间不能有未被占领的城市,其中c1是首都的位置。问我们占领所有的城市所需要的最小代价(最后首都的位置无所谓)

分析:首先我们可以知道我们将首都从0号点直接迁至k号点花费的代价和从0号点经过若干次迁都到达k号点所花费的代价是相同的(前提是每次迁都的方向都是沿着x轴正方向),那么我们可以发现为了使得占领城市的代价尽量小,我们就要使得首都的位置尽量靠近我们要占领的城市。假如最优结果中首都的位置是k号点,那么在占领前k个城市中每占领一个城市我们就将首都迁至这个位置,这样一定是最优的,这也是很容易理解的,因为我们保证了每次占领城市所需要的代价都是最小的,而迁都的代价又是固定的,剩余的未被占领的城市直接都相对于k号点进行占领即可。所以我们的目的就是枚举最后的首都的位置然后直接对于每个位置O(1)求代价即可,我们需要预处理一些信息。

详情见代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
long long p[N];
long long s[N];
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		long long n,a,b;
		scanf("%lld%lld%lld",&n,&a,&b);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&p[i]);
			s[i]=s[i-1]+p[i];
		}
		long long ans=s[n]*b;
		for(int i=1;i<n;i++)
			ans=min(ans,p[i]*a+p[i+1]*b+(s[n]-s[i+1]-(n-i-1)*p[i])*b);
		printf("%lld\n",ans);
	}
	return 0;
}

D. Reverse Sort Sum

题目链接:Problem - D - Codeforces

样例输入:

5
4
2 4 2 4
7
0 3 4 2 3 2 7
3
0 0 0
4
0 0 0 4
3
1 2 3

样例输出:

1 1 0 1 
0 1 1 0 0 0 1 
0 0 0 
0 0 0 1 
1 0 1 

题意:定义f(k,A)是将A数组前k个元素按照非递降顺序排序后的数组。其中A数组是一个由01字符组成的数组。现在已知B数组,其中B=\sum_{k=1}^{n}f(k,A),求解A数组。

分析:这个我们可以倒着进行考虑,先考虑第n个数,如果第n个数是等于n的,那么说明第n个位置A数组元素的值是1,如果B数组中第n个位置的值是等于0的,说明A数组中所有元素都等于0,如果B[n]=1,说明A[n]=1.第n次排序后的数组一定是0000……111这种形式,而且数组中1的个数我们是能够直接求出来的,所以我们就可以知道前n-1次排序的结果,也就是用b[1~n]-0000……111,其中1的初始位置我们是可以通过1的个数推出来的,但是这个地方不能暴力减,我们需要用数组数组维护差分进行优化。能够发现第n个位置的值并不会影响前n-1次排序的结果,所以这个时候第n个位置的影响我们就已经分析完了,这个时候我们就需要来分析一下前n-1个数的情况了,这是相同的问题,所以我们只需要按照上面方法倒着分析每一位的情况即可。

细节见代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
int a[N],b[N],c[N];
int n;
int lowbit(int x)
{
	return x&-x;
}
void add(int x,int val)
{
	for(int i=x;i<=n;i+=lowbit(i))
		c[i]+=val;
}
int sum(int x)
{
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
		ans+=c[i];
	return ans;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		scanf("%d",&n);
		long long s=0;
		for(int i=1;i<=n;i++)
			scanf("%d",&b[i]),s+=b[i],a[i]=c[i]=0;
		for(int i=1;i<=n;i++)
			add(i,b[i]-b[i-1]);
		long long cnt=s/n;
		for(int i=n;i>=1;i--)
		{
			b[i]=sum(i);
			if(b[i]==i)
			{
				a[i]=1;
				add(i-cnt+1,-1);
				add(i+1,1);
				cnt--;
			}
			else if(b[i]==1)
			{
				add(i-cnt+1,-1);
				add(i+1,1);
			}
			else
				break;
		}
		for(int i=1;i<=n;i++)
			printf("%d ",a[i]);
		puts("");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值