Codeforces Round #592 (Div. 2)

Codeforces Round #592 (Div. 2)
A.B略
C.The Football Season
题意: 给你w,d,p,n,是否存在同时满足等式

  1. x ∗ w + y ∗ d = p x*w+y*d=p xw+yd=p
  2. x + y + z = n x+y+z=n x+y+z=n
    思路: 因为1<d<w<1e5,故只要枚举d从一到1到w是否有符合的情况即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	ll n,p,d,w;
	scanf("%lld%lld%lld%lld",&n,&p,&w,&d);
	if(w*n<p||p%__gcd(w,d))
	{
		puts("-1");
		return 0;
	}
	else
	{
		if(p%w==0)
		{
 
			printf("%lld %lld %lld\n",p/w,0ll,n-p/w);
			return 0;
		}
		for(int i=1;i<w;i++)
		{
			if((p-i*d)%w==0)
			{
				ll x=(p-i*d)/w;
 
				if(x>=0&&x+i<=n)
				{
 
					printf("%lld %d %lld\n",x,i,n-x-i);
 
					return 0;
				}
			}
		}
	}
	puts("-1");
	return 0;
}

D. Paint the Tree
题意: 给你一颗树,每个结点都有三个颜色点权,且相连的三个点不能有相同的颜色,问染整棵树的最小值为多少?
思路: 只有一条链的时候才存在方案,并且考虑在链上的话,前两个点的颜色确定了,那么整条链的颜色都确定了。所以暴力六种情况取其中最小即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int a[N][4];
vector<int>G[N];
int vis[N];
int res[N];
ll ans;
ll tmp;
void dfs1(int u,int fa,int x,int y)
{
	vis[u]=y;
	tmp+=a[u][y];
 
	for(auto v:G[u])
	{
		if(v==fa)
			continue;
		dfs1(v,u,y,6-x-y);
	}
}
 
void dfs(int i,int j)
{
 
	vis[i]=1;
	tmp=a[i][1];
	dfs1(j,i,1,2);
	memcpy(res,vis,sizeof vis);
	ans=tmp;
	vis[i]=1;
	tmp=a[i][1];
	dfs1(j,i,1,3);
	if(ans>tmp)
	{
		ans=tmp;
		memcpy(res,vis,sizeof vis);
	}
 
	vis[i]=2;
	tmp=a[i][2];
	dfs1(j,i,2,1);
	if(ans>tmp)
	{
		ans=tmp;
		memcpy(res,vis,sizeof vis);
	}
 
	vis[i]=2;
	tmp=a[i][2];
	dfs1(j,i,2,3);
	if(ans>tmp)
	{
		ans=tmp;
		memcpy(res,vis,sizeof vis);
	}
 
	vis[i]=3;
	tmp=a[i][3];
	dfs1(j,i,3,1);
	if(ans>tmp)
	{
		ans=tmp;
		memcpy(res,vis,sizeof vis);
	}
 
	vis[i]=3;
	tmp=a[i][3];
	dfs1(j,i,3,2);
	if(ans>tmp)
	{
		ans=tmp;
		memcpy(res,vis,sizeof vis);
	}
 
}
 
int main()
{
	int n;
	scanf("%d",&n);
	for(int j=1;j<=3;j++){
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i][j]);
		}
	}
	for(int i=1;i<=n-1;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	int flag;
	for(int i=1;i<=n;i++)
	{
		if(G[i].size()>2)
		{
			puts("-1");
			return 0;
		}
		if(G[i].size()==1)
			flag=i;
	}
	//cout<<flag<<G[flag][0]<<endl;
	dfs(flag,G[flag][0]);
	printf("%lld\n",ans);
	for(int i=1;i<=n;i++){
		printf("%d ",res[i]);
	}
	puts("");
	return 0;
}

E. Minimizing Difference
题意: 给你一个数组,每次操作可以使其中一个元素+1或-1,问最多有k次操作,使得数组中max-min最小
思路: 将数组排序后,同时从两个方向一个一个移动即可

	#include<bits/stdc++.h>
	using namespace std;
	typedef long long ll;
	const int N=1e5+5;
	int a[N];
	int main()
	{
		int n;
		ll k;
		scanf("%d%lld",&n,&k);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		sort(a+1,a+1+n);
 
		for(int i=1;i<=n/2;i++)
		{
			ll cnt=1ll*(a[i+1]-a[i]+a[n-i+1]-a[n-i])*i;
			if(k>=cnt){
				k-=cnt;
			}
			else {
				printf("%lld\n",1ll*(a[n-i+1]-a[i]-k/i));
				return 0;
			}
		}
		printf("0\n");
		return 0;
	}

F. Chips
题意: 给出一个环,每个点有黑白两色,然后有k操作,每次操作是这样的:
如果一个点两边的颜色有一个和自己相同,那么这个点的颜色不变,否则这个点的颜色翻转,黑变白,白变黑。
问k次操作后每个点的颜色。
思路: 我们可以得知当有两个相邻点颜色一样,则永远不会翻转,然后向两端扩展,每次+1最后可以得到每个点在第几次不会再翻,一种除外WBWBWB这种
注意向两端拓展着用跑两遍,我被这个卡了很久

#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
char str[200010];
int tim[200010];
int main()
{
	memset(tim,0x3f,sizeof(tim));
	int n,k;scanf("%d %d",&n,&k);
	scanf("%s",str);
	for(int i=0;i<n;i++)
		if(str[i]==str[(i+1)%n]||str[i]==str[(i-1+n)%n])
			tim[i]=0;
	for(int i=0;i<2*n;i++)
		tim[i%n]=min(tim[i%n],tim[(i-1+n)%n]+1);
	for(int i=2*n-1;i>=0;i--)
		tim[i%n]=min(tim[i%n],tim[(i+1)%n]+1);
	for(int i=0;i<n;i++)
		if(min(tim[i],k)&1)
			printf("%c",'W'+'B'-str[i]);
		else printf("%c",str[i]);
	printf("\n");
	return 0;
}

/*
16 2
WBWBWBBBWBWBWBWB
*/

G. Running in Pairs
题意: 构造两个排列,使得 ∑ i = 1 n m a x ( p i , q i ) < = k \sum_{i=1}^{n}max(p_i,q_i)<=k i=1nmax(pi,qi)<=k,且使得结果尽可能的大
思路: 首先我们确定一个排列为1……n,接着构造第二个排列,我们可以知道sum最小为两个排列一模一样(n+1)*n/2,
考虑第二个排列刚开始也是顺序排放的。
然后考虑交换位置视为元素左移和元素右移。
显然,元素右移不会对答案产生影响。
但是元素左移,左移几个位置它就产生多少贡献。
那么显然可以发现这个变化是连续的,直接贪心即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll n,k;
int a[N];
int main()
{
	scanf("%lld%lld",&n,&k);
	ll sum=n*(n+1)/2;
	if(k<sum)
	{
		puts("-1");
		return 0;
	}
	k-=sum;
	for(int i=1;i<=n;i++)
		a[i]=i;
	int tmp=n;
	for(int i=1;i<=n&&i<tmp;i++)
	{
		int res=tmp-i;
		if(res<=k)
		{
			sum+=res;
			k-=res;
			swap(a[i],a[tmp]);
			tmp--;
		}
	}
	printf("%lld\n",sum);
	for(int i=1;i<=n;i++)
		printf("%d ",i);
	puts("");
	for(int i=1;i<=n;i++)
		printf("%d ",a[i]);
	puts("");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值