hgoi#20191108

T2-能量传输

\(n\) 个人排成一圈,每恰好相隔 \(k\) 个人可以花费 \(1\) 的代价传输 \(1\) 的能量。
给出每个人的初始能量,为了使得每个人最终的能量都相等,输出最小代价。

解法

如果不是相隔 \(k\) 个人,而是相邻的人
这题就是个环形均分纸牌
至于这玩意的解法,这里不作解释QWQ
那相隔 \(k\) 个人怎么办呢
我们考虑每次跳 \(k\) 个人并以此来重构这个序列
然后对于所有重构出的序列,做一遍环形均分纸牌即可

ac代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,ans,a[500010],b[500010],f[500010];
bool tg[500010];
int calc(int a[500010],int n)
{
	int ans=0;
	for(int i=1;i<=n;i++)
		a[i]-=a[0]/n,f[i]=f[i-1]+a[i];
	sort(f+1,f+n+1);
	for(int i=1;i<=n;i++)
		ans+=abs(f[i]-f[n+1>>1]);
	return ans;
}
signed main()
{
	freopen("energy.in","r",stdin);
	freopen("energy.out","w",stdout);
	scanf("%lld%lld",&n,&k),k++;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int st=1;st<=n;st++)if(!tg[st])
	{
		int i,nw;
		for(i=1,nw=st,b[0]=0;;i++,nw=(nw+k-1)%n+1)
			if(tg[nw])break;
			else b[i]=a[nw],tg[nw]=1,b[0]+=b[i];
		ans+=calc(b,i-1);
	}
	printf("%lld\n",ans);
	return 0;
} 

T3-矿物运输

给出一棵有 \(n\) 个点的树,每一个点上面有一个权值 \(val_i\)
先手和后手轮流操作,使得一个节点上 \(1\) 的权值移到它的父亲节点上、
无法移动的人判负,先手胜利输出"win"否则输出"lose"

解法

一个很显然的最优策略,对于偶数层,它做什么,我们做什么即可
对于奇数层,考虑到做一次就会变成偶数层的,也就是上一种情况
所以就和取石子的那种nim游戏一样了
将奇数层的权值 \(xor\) 起来,如果有值就是win

ac代码

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
vector<int>e[200010];
int T,n,x,ans,a[200010],d[200010];
void dfs(int u)
{
	for(auto v:e[u])
		d[v]=d[u]+1,dfs(v);
}
int main()
{
	freopen("ore.in","r",stdin);
	freopen("ore.out","w",stdout);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			vector<int>().swap(e[i]);
		for(int i=1;i<n;i++)
			scanf("%d",&x),e[x].pb(i);
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		dfs(0),ans=0;
		for(int i=0;i<n;i++)
			if(d[i]&1)ans^=a[i];
		puts(ans?"win":"lose");
	}
	return 0;
} 
posted @ 2019-11-08 16:07  可耐滴小慕容  阅读(97)  评论(0编辑  收藏  举报