2021.11.18 部分题解

翻转游戏

solution:

有一种理解,就是当前需要消除的1数目为偶数,那么就一定没有方案。
那么我们来考虑奇数情况,将 m m m写成二进制形式,然后我们把每个1和前面连续的0看成一块,第一个1就除外
若一个1前面没有0那么就直接添加就可以了
如图,我们需要的只是 1 1 1这一段的长度,要得到这个长度,我们就用 O 3 − O 2 − O 1 − 1 O3-O2-O1-1 O3O2O11,得到的就是 1 1 1串的长度
在这里插入图片描述

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+10;
int n,m,ans[N];
void work(){
	if(!(m&1)){puts("NO");return;}
	ans[0]=0;
	int cnt=0,l=1,flag=0;
	for(int i=31;i>=0;i--){
		if((m>>i)&1){
			if(!cnt||!flag)ans[++ans[0]]=l;
			else{
				int tmp = l;
				for(int j=0;j<cnt;j++){
					tmp=tmp-(1<<(i+j));
					ans[ans[0]+cnt+1-j]=tmp;
				}ans[ans[0]+1]=tmp;
				ans[0]+=cnt+1;
			}cnt=0;flag=1;l+=(1<<i);
		}else cnt++;
	}puts("YES");printf("%d\n",ans[0]);
	for(int i=ans[0];i>=1;i--)printf("%d ",ans[i]);
	puts("");
}
int main(){
//	freopen("flip.in","r",stdin);
//	freopen("flip.out","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		if(!m){puts("YES");puts("0");}
		else work();
	}
	return 0;
}

路径乘积

solution:

如果存在1,那最优的答案要么是最长的1链,要么是一个2链接两个等长的1链(自证不难

#pragma GCC optimize(3)
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define P pair<ll,ll>
#define fi first 
#define se second
using namespace std;
const int N = 2e6+10;
int n,m;
ll a[N],mi,f[N],g[N];
int en[N],nex[N],lst[N],tot,son[N];
void add(int x,int y){en[++tot]=y;nex[tot]=lst[x];lst[x]=tot;}
P ans;
void change(P a,P b,P &c){c=(a.fi*b.se<b.fi*a.se)?a:b;} 
void dfs(int u,int fa){
	for(int i=lst[u];i;i=nex[i]){
		int v=en[i];
		if(v==fa)continue;
		dfs(v,u);f[u]=max(f[v],f[u]);
	}if(a[u]==1)f[u]++;else f[u]=0;
}
void get(int u,int fa){
	int smx(0);
	for(int i=lst[u];i;i=nex[i]){
		int v=en[i];
		if(f[v]>=g[u])smx=g[u],g[u]=f[v],son[u]=v;
		else if(f[v]>smx)smx=f[v];
	}
	if(a[u]==1){g[u]++;smx++;P now=P(1,g[u]+smx-1);change(now,ans,ans);}
	if(a[u]==2&&g[u]==smx){P now=P(2,g[u]+smx+1);change(now,ans,ans);}
	if(a[u]!=1)g[u]=smx=0;
	for(int i=lst[u];i;i=nex[i]){
		int v=en[i];if(v==fa)continue;
		if(v==son[u])f[u]=smx;else f[u]=g[u];
		get(v,u);
	}
}
signed main(){
	scanf("%d",&n);mi=1e9+1;
	for(int i=1;i<n;i++){
		int x,y;scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}for(int i=1;i<=n;i++)scanf("%lld",a+i),mi=min(a[i],mi);
	ans=P(mi,1);dfs(1,0);get(1,0);
	printf("%lld/%lld\n",ans.fi,ans.se);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值