翻转游戏
solution:
有一种理解,就是当前需要消除的1数目为偶数,那么就一定没有方案。
那么我们来考虑奇数情况,将 m m m写成二进制形式,然后我们把每个1和前面连续的0看成一块,第一个1就除外
若一个1前面没有0那么就直接添加就可以了
如图,我们需要的只是 1 1 1这一段的长度,要得到这个长度,我们就用 O 3 − O 2 − O 1 − 1 O3-O2-O1-1 O3−O2−O1−1,得到的就是 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;
}