Codeforces Round #646 (Div. 2) ABCE

A:

1.没有奇数肯定不行

2.有奇数无偶数,判断x是否奇数

3.有奇数有偶数,判断x是否等于n,

等于n则判断奇数个数是否是奇数

否则一定可以(可以通过改变加奇数个数来改变奇偶性,因为至少一个偶数)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;

int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}


int a[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
	  cin>>t;
	 while(t--)
	 {
	 	int n,x;
	 	cin>>n>>x;
	 	int o=0,e=0;
	 	for(int i=1;i<=n;i++)
	 	{
	 		cin>>a[i];
	 		if(a[i]&1)o++;
	 		else e++;
		 }
		if(o)
		{
			if(e)
			{
				if(x==n)
				{
					if(o&1)cout<<"YES"<<endl;
					else cout<<"NO"<<endl;
				}
				else cout<<"YES"<<endl;
			}
			else
			{
				if(x&1)cout<<"YES"<<endl;
				else cout<<"NO"<<endl;
			}
		}
		else cout<<"NO"<<endl;
	  } 
	return 0;
}

B:

显然只有 000111 ,111000的形式 暴力枚举即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;

int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}


char s[1100];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--)
	{
		cin>>s;
		int n=strlen(s);
		int mi=10000;
		for(int i=0;i<=n;i++)
		{
			int ans=0;
			for(int j=0;j<i;j++)if(s[j]=='1')ans++;
			for(int j=i;j<n;j++)if(s[j]=='0')ans++;
			mi=min(ans,mi);
			ans =0;
			for(int j=0;j<i;j++)if(s[j]=='0')ans++;
			for(int j=i;j<n;j++)if(s[j]=='1')ans++;
			mi=min(ans,mi);
		}
		cout<<mi<<endl;
	}
	return 0;
}

C:

当x是叶子节点时先手必胜,n==1时,x一定是叶子节点。

否则,双方都不愿意把x的度数变为1,都会尽量删去其他边。这样就只需要考虑边数的奇偶性即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e3+7;

int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}


int du[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--)
  	{
  		memset(du,0,sizeof(du));
  		int n,x;
  		cin>>n>>x;
  		for(int i=1;i<n;i++)
  		{
  			int u,v;
  			cin>>u>>v;
  			du[u]++;
  			du[v]++;
		}
		bool f=true;//先手是否赢 
		if(du[x]==1||n==1)f=true;
		else
		{
			if((n-1)&1)f=true;
			else f=false;
		}
	//	cout<<(n-1)<<" "<<f<<endl;
		if(!f)cout<<"Ashish"<<endl;
		else cout<<"Ayush"<<endl;
	}
	return 0;
}

E:

显然:只有0-1(初始为0,目标为1)  和1-0的个数相同,才能通过交换顺序来达到所有的目标。

考虑下图:

A表示  需要0-1,B表示1-0,C表示初始和目标都相同 。

如果A的数量等于B的数量,我们直接对1节点进行操作,至少可以保证有解。记录当前花费ans

显然ans不一定是最优解。

我们可以选择5(如果a[5]<a[1]),使得6,7节点交换。这样的结果一定小于ans。(相当于在节点1,交换了 1,2,3,5,在节点5交换了 6,7)

综上就有了如下做法:

先预处理s1[x],s2[x],表示x的子树中,A的个数/B的个数。

枚举所有节点x,判断a[x]是否小于所有x的父辈节点y的a[y],(即a[x]小于所有的a[y].)

如果节点x满足a[x]<a[y],则我们让ans-=a[x]*mia[x]*2。ans+=a[x]*min(s1[x],s2[x])*2;  (mia[x]表示最小的a[y])

即,在x点对x子树中的 AB交换优于,在x的父辈点,对x子树中AB交换。

枚举完所有节点就可得出最小的ans。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;

int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}


ll a[M],b[M];
ll s1[M],s2[M],mia[M];
void dfs(int x,int fa)
{
	if(b[x]==1)s1[x]++;
	if(b[x]==2)s2[x]++;
	for(int i=head[x];i;i=ee[i].nxt)
	{
		int y=ee[i].to;
		if(y==fa)continue;
		mia[y]=min(a[y],mia[x]);
		dfs(y,x);
		s1[x]+=s1[y];s2[x]+=s2[y];
	}
}
ll ans;
void gao(int x,int fa)
{
	if(fa)
	{
		//cout<<x<<"  "<<a[x]<<" "<<mia[fa]<<endl;
		if(a[x]<mia[fa])
		{
			ll nm=min(s1[x],s2[x])*2;
			ans-=nm*mia[fa];
			ans+=nm*a[x];
		}
	}
	for(int i=head[x];i;i=ee[i].nxt)
	{
		int y=ee[i].to;
		if(y==fa)continue;
		gao(y,x);
	}
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n,u,v;
  	cin>>n;
  	for(int i=1;i<=n;i++)
  	{
  		int x,y;
  		cin>>a[i]>>x>>y;
  		if(x==y)b[i]=0;
  		else if(x)b[i]=1;
  		else b[i]=2;
	}
	for(int i=1;i<n;i++)cin>>u>>v,add(u,v,1),add(v,u,1);
	mia[1]=a[1];dfs(1,0);
	if(s1[1]!=s2[1])
	{
		cout<<-1<<endl;
		return 0;
	}
//	for(int i=1;i<=n;i++)
//		cout<<i<<"  "<<" "<<s1[i]<<"   "<<s2[i]<<" "<<mia[i]<<endl;
	ans=s1[1]*a[1]*2;
//	cout<<ans<<" -- "<<endl;
	gao(1,0);
	cout<<ans<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值