QOJ 7607. The Doubling Game 2
题意
\(n\) 个节点的树,每个节点上初始有权值 \(val=1\),若存在无向边 \((u,v)\) 且 \(val_u=val_v\),则能操作 \(val_u\gets val_u+val_v\),\(val_v\gets 0\)。求最终树的形态数。
solution
考虑将每次操作 \(val_u\) 转移至 \(val_v\) 连边 \(u\to v\),则最终图形如给原树生成子图中的边定向,且每个点最多有一条出边(向外转移一次后 \(val=0\) 后始终不变,转移没有意义)。则必定为内向树森林,而每棵内向树的操作均为子节点向父亲转移,最终所有权值全在根节点,故形态唯一。
问题转化为给原图边定向或删去,求有标号生成子图形态数。
考虑转移操作 \(u\to v\),则要求 \(val_u=val_v\),假设 \(val_u=2^x\) 则 \(v\) 连向的其他节点需分别存在向 \(v\) 转移 \(2^{0,1,\cdots,x-1}\) 使得 \(val_v=val_u\)。这个限制不是很好做考虑状压。
设定状态 \(f_{u,i},g_{u,i},w_u\) 分别表示 \((u,fa)\) 的边方向为 \(u\to v/v\to u\) 转移了 \(2^i\) 的权值或是不操作。
转移讨论 \(u\) 向每个子节点边的情况,细节比较多。
每个节点最多向父节点转移 \(siz\) 的权值,故时间复杂度约为 \(O((\sum 2^{\log siz})\cdot \log n)\) 量级,其中后者是转移的复杂度,显然最劣 \(O(n^2\log n)\)。
而与 \(siz\) 有关考虑重链剖分,对于轻儿子的 \(\sum 2^{\log siz}=n\log n\),而 \(u\) 的重儿子实际上向父节点转移的权值最多为 \(u\) \(siz\) 最大的轻儿子的最大转移权值的 2 倍(否则若转移不合法的 \(2^x\),则所有轻儿子转移不出 \(2^{0,1,\cdots,x}\) 使得 \(val_u=val_{son_u}\),必定无法转移)。这个结论将状压的复杂度优化至 \(O(2^{\log (n\log n)}\log n)=O(n\log ^2 n)\)。
Takanashi Rikka
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
using namespace __gnu_pbds;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){
ll x=0,f=1;char ch=nc();
while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
#define pcount(x) __builtin_popcount(x)
inline void cmx(auto &x,ll y){if(y>x)x=y;}
inline void cmn(auto &x,ll y){if(y<x)x=y;}
inline int max(vector<int>w){int res=-1e9;for(int i:w)cmx(res,i);return res;}
const int mod=1e9+7;
ll qp(ll x,int y){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
const int N=3e5+5;
#define int ll
vector<int>e[N];
int siz[N],f[N][20],g[N][20],w[N],tf[N],tg[N],lg[N];
void dfs(int u,int fa){
vector<int>p;siz[u]=1;
for(int v:e[u])if(v^fa)
dfs(v,u),siz[u]+=siz[v],p.pb(v);
sort(p.begin(),p.end(),[&](int x,int y){return siz[x]<siz[y];});
int lst=0,tmp=0,mx=0;tf[0]=1;
for(int v:p){
tmp=min(lg[siz[v]],(p.size()>1?lg[siz[p[p.size()-2]]]+2:1));
for(int i=0,V;i<(1<<mx);i++){
V=tg[i],tg[i]=tg[i]*w[v]%mod;
for(int j=0;j<=tmp;j++)if(i&(1<<j))
(tg[i^(1<<j)]+=V*f[v][j]%mod)%=mod;
}
for(int i=(1<<mx)-1,V;~i;i--){
V=tf[i],tf[i]=tf[i]*w[v]%mod;
for(int j=0;j<=tmp;j++){
if(!(i&(1<<j)))
(tf[i^(1<<j)]+=V*f[v][j]%mod)%=mod;
if((1<<j)-i-1>=0)
(tg[(1<<j)-i-1]+=V*g[v][j]%mod)%=mod;
}
}
mx=max(mx,tmp+1);
}
(w[u]+=tg[0])%=mod;
for(int i=0;i<(1<<mx);i++)
if(pcount(i)==1)
(g[u][lg[i]]+=tg[i])%=mod;
for(int i=0;i<(1<<mx);i++){
if(pcount(i+1)==1)
(w[u]+=tf[i])%=mod,
(f[u][lg[i+1]]+=tf[i])%=mod;
for(int j=0;j<20;j++)
if((1<<j)-i-1>=0&&pcount((1<<j)-i-1)==1)
(g[u][lg[(1<<j)-i-1]]+=tf[i])%=mod;
}
for(int i=0;i<=(1<<mx);i++)tf[i]=tg[i]=0;
}
inline void UesugiErii(){
int n;cin>>n;
for(int i=1,u,v;i<n;i++)
cin>>u>>v,e[u].pb(v),e[v].pb(u);
for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
dfs(1,0);cout<<w[1];
}
signed main(){
//IO();//cfast;
int _=1;//cin>>_;
for(;_;_--)UesugiErii();
return 0;
}

浙公网安备 33010602011771号