Codeforces Round #782 (Div. 2)

A. Red Versus Blue

题意:
红队和蓝队比赛,红队赢 r r r局,蓝队赢 b b b ( r > b ) (r>b) (r>b),由于比赛过程势均力敌,请你构造出合适的字符串使红队的最长连胜最小
思路:
考虑在蓝队的 b b b局共 b + 1 b+1 b+1个空位均值插入 r r r即可

#include<bits/stdc++.h>
#define pb push_back
#define inf 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<int,int> PII;
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,r,b;
		scanf("%d%d%d",&n,&r,&b);
		int num=r/(b+1);
		int mod=r%(b+1);
		for(int i=1;i<=b+1;i++)
		{
			for(int j=1;j<=num;j++) printf("R");
			if(i<=mod) printf("R");
			if(i!=(b+1))
			printf("B");
		}
		puts("");
	}
}

B. Bit Flipping

题意:
给你一串长度 n n n 01 01 01串,以及 k k k次操作,每次操作会使除了选定的位置不变,其余的位置均翻转,求 k k k次操作后可以得到的字典序最大的串以及 n n n个点上每个点的操作次数
思路:
从高位向低位贪心,若对某个位置进行了 p p p次操作,则意味着该位置会翻转 k − p k-p kp次,根据奇偶关系尽可能使高位变为 1 1 1。若操作完前 n − 1 n-1 n1位后仍有剩余操作,则全部操作给第 n n n

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+7;
char s[maxn];
int a[maxn];
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,k;
		scanf("%d%d%s",&n,&k,s+1);
		for(int i=1;i<=n;i++) a[i]=0;
		int num=k;
		for(int i=1;i<n;i++)
		{
			if(num>0)
			{
				if(s[i]=='1')
				{
					if(k%2==0) continue;
					else a[i]++,num--;
				}
				else
				{
					if(k%2==1)
					{
						s[i]='1';continue;
					}
					else a[i]++,num--,s[i]='1';
				}
			}
			else
			{
				if(k%2)
				{
					if (s[i]=='1') s[i]='0';
					else s[i]='1';
				}
			}	
		}
		a[n]=num;
		if(k%2)
		{
			if(num%2==0)
			{
				if(s[n]=='1') s[n]='0';
				else s[n]='1';
			}
		}
		else
		{
			if(num%2)
			{
				if(s[n]=='1') s[n]='0';
				else s[n]='1';
			}
		}
		printf("%s\n",s+1);
		for(int i=1;i<=n;i++) printf("%d ",a[i]);
		puts("");
	}
}

C. Line Empire

题意:
你的王国在 0 0 0的位置上,首都位置为 c a p = 0 cap=0 cap=0,此外在大于 0 0 0的位置 x 1 . . . x n x_1...x_n x1...xn上还有 n n n个王国,为了征服这 n n n个王国,你可以

  • 占领一座王国,花费 b ∗ ∣ c a p − x ∣ b*\left|cap-x\right| bcapx
  • 将首都移到一个已经占领的王国,花费 a ∗ ∣ c a p − x ∣ a*\left|cap-x\right| acapx

求全部占领的最小花费
思路:
考虑最终的首都在 x i x_i xi,迁都的总花费为 a ∗ ∣ x i − 0 ∣ a*\left|x_i-0\right| axi0,等价于 a ∗ ∣ x i − x i − 1 ∣ + a ∗ ∣ x i − 1 − x i − 2 ∣ . . . a*|x_i-x_{i-1}|+a*|x_{i-1}-x_{i-2}|... axixi1+axi1xi2...
即若首都最终在 x i x_i xi,结果等价于将首都依次从 x 1 x_1 x1移动到 x i x_i xi,于是只需要枚举首都最终的位置,就可以确定各个情况的操作过程,直接计算即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
ll x[maxn],sum[maxn];
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		ll n,a,b;
		scanf("%lld%lld%lld",&n,&a,&b);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&x[i]);
			sum[i]=sum[i-1]+x[i];
		}
		ll ans=sum[n]*b,res=0;
		for(int i=1;i<=n;i++)
		{
			res+=(a+b)*(x[i]-x[i-1]);
			ll temp=res+b*(sum[n]-sum[i]-x[i]*(n-i));
			ans=min(ans,temp);
		}
		printf("%lld\n",ans);
	}
}

D. Reverse Sort Sum

题意:
给你长度为 n n n 01 01 01数组 A A A f ( k , A ) f(k,A) f(k,A)表示将 A A A中的前 k k k位按大小排序,返回为排好序的数组 B B B
数组 C C C f ( 1 , A ) + f ( 2 , A ) + . . . + f ( n , A ) f(1,A)+f(2,A)+...+f(n,A) f(1,A)+f(2,A)+...+f(n,A)
告诉你数组 C C C,请为之构造合适的数组 A A A
思路:
C C C中所有元素相加,除以 n n n,得到 c n t cnt cnt A A A中数字 1 1 1出现的次数
考虑倒序思考,若在前 i i i位中有 c n t cnt cnt 1 1 1,则可使 C C C [ i − c n t + 1 , i ] [i-cnt+1,i] [icnt+1,i]区间减一,操作完成后若 C i C_i Ci依然大于 0 0 0,则说明 A i = 1 A_i=1 Ai=1,同时更新维护 c n t cnt cnt

#include<bits/stdc++.h>
#define lowbit(x) x&-x
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
int c[maxn],a[maxn],add[maxn],n;
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		ll sum=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&c[i]);
			sum+=c[i];a[i]=0;add[i]=0;
		}
		int cnt=sum/n,del=0;
		for(int i=n;i>=1;i--)
		{
			if(cnt==0) break;
			del--;
			add[i-cnt]++;
			del+=add[i];
			if(c[i]+del>0) cnt--,a[i]=1;
		}
		if(cnt) a[1]=1;
		for(int i=1;i<=n;i++) printf("%d ",a[i]);
		puts("");
	}
}

E. AND-MEX Walk

题意:
给你 n n n个点 m m m条边的无向连接图,点 u u u v v v的权值为 w w w
从点 a a a到点 b b b所走路径上权值为 { w 1 , w 2 . . . w k } \{w_1,w_2...w_k\} {w1,w2...wk},花费为 m e x ( { w 1 , w 1 & w 2 , . . . , w 1 & w 2 & . . . & w k } ) mex(\{w_1,w_1\&w_2,...,w_1\&w_2\&...\&w_k\}) mex({w1,w1&w2,...,w1&w2&...&wk})
接下来有 q q q次询问,每次回答从 a a a b b b的花费
思路:
对于答案,只可能是 0 , 1 , 2 0,1,2 0,1,2三种情况
将该无向图按照权值的二进制位分解为 30 30 30个子图,每一位的子图上只有权值在这一位上为 1 1 1才可以连接

  • 若答案为 0 0 0,则要求有一位在该路径上始终出现,对 30 30 30个图使用并查集判断,看看是否在某一位的子图上 a a a b b b相连,则说明该位始终出现
  • 若答案为 1 1 1,则说明不存在上述情况。对于除了第 0 0 0位的其他位上的子图,若从起点开始,可以到达一条偶数边,则说明第 0 0 0位上的 1 1 1已经被完全消除,随后可以在连通图上随意移动,都不可能会再出现 1 1 1
  • 若上述两种情况均不可,则答案为 2 2 2
#include<bits/stdc++.h>
#define pb push_back
typedef long long ll;
using namespace std;
const int maxn=1e5+7;
int n,m,vis[maxn],ok[35][maxn];
vector<int>v[maxn];
struct DSU
{
	int fa[maxn],p[maxn];
	void init()
	{
		for(int i=1;i<=n;i++) fa[i]=i,p[i]=0;
	}
	int find(int x)
	{
		if(fa[x]==x) return x;
		else return fa[x]=find(fa[x]);
	}
	void connect(int x,int y)
	{
		int px=find(x),py=find(y);
		fa[px]=py;
	}
}g[35];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<=30;i++) g[i].init();
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		if(c%2==0) vis[a]=1,vis[b]=1;
		v[a].pb(b);v[b].pb(a);
		for(int j=0;j<=30;j++)
		{
			if(c>>j&1)
			{
				g[j].connect(a,b);
			}
		}
	}
	for(int i=1;i<=n;i++) 
	{
        if (vis[i])
		{
            for(int j=1;j<=30;j++) 
			{
                ok[j][g[j].find(i)]=1;
            }
        }
    }
	int q;
	scanf("%d",&q);
	while(q--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		int flag=0;
		for(int i=0;i<=30;i++)
		{
			if(g[i].find(a)==g[i].find(b))
			{
				flag=1;break;
			}
		}
		if(flag)
		{
			puts("0");continue;
		}
		for(int i=0;i<=30;i++)
		{
			if(ok[i][g[i].find(a)]) flag=1;
		}
		if(flag) puts("1");
		else puts("2");
	}
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值