标签:val 时移 main 移动 pool etc type 深度 include
结论:后手必胜当且仅当根节点为直径中点。
根节点为直径中点:
如果两人都在直径上移动,那么不论先手如何移动,后手总能移动到对称的位置。
如果先手移出了直径,设这一点与根节点的距离为\(x\),那么后手仍然回到直径上距离根节点\(x\)的点。
其它的情况先手只需移动至直径中点(当直径中点在边上时移动至该边的一端),然后按照上面的策略即可。
那么我们现在要求的就是直径中点为根节点的连通块个数。
设\(f_{u,i}\)表示\(u\)的子树中最大深度为\(i\)的子图的方案数,长链剖分优化dp即可。
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
const int N=200007,P=1000000007;
int n,son[N],dep[N];std::vector<int>e[N];
struct node{int val,tag;node(){val=0,tag=1;}}pool[N*4],*now=pool,*f[N],g[N];
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int add(int a,int b){return inc(a,b),a;}
int mul(int a,int b){return 1ll*a*b%P;}
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void dfs(int u,int fa){for(int v:e[u])if(v^fa)if(dfs(v,u),dep[v]+1>dep[u])dep[u]=dep[son[u]=v]+1;}
void alloc(int u){f[u]=now,now+=dep[u]+2;}
void modify(node*a,int x){a->tag=mul(a->tag,x),a->val=mul(a->val,x);}
void pushdown(node*a){if(a->tag^1) modify(a+1,a->tag),a->tag=1;}
void dp(int u,int fa)
{
if(f[u][0].val=1,!son[u]) return ;
f[son[u]]=f[u]+1,dp(son[u],u);
for(int v:e[u])
if(v^fa&&v^son[u])
{
alloc(v),dp(v,u);int len=dep[v]+1;
if(u^1)
{
int r=1,s=1;
for(int i=1;i<=len;++i) pushdown(f[u]+i),pushdown(f[v]+i-1),inc(r,f[u][i].val),f[u][i].val=add(mul(r,f[v][i-1].val),mul(s,f[u][i].val)),inc(s,f[v][i-1].val);
modify(f[u]+len+1,s);
}
else
{
int r=1,s=1,t=0;
for(int i=1,t1,t2;i<=len;++i)
{
pushdown(f[u]+i),pushdown(g+i),pushdown(f[v]+i-1);
t1=add(mul(add(r,t),f[v][i-1].val),mul(s,f[u][i].val));
t2=add(mul(s,g[i].val),mul(add(g[i].val,f[u][i].val),f[v][i-1].val));
inc(r,f[u][i].val),inc(s,f[v][i-1].val),inc(t,g[i].val);
f[u][i].val=t1,g[i].val=t2;
}
modify(f[u]+len+ 1,s),modify(g+len+1,s);
}
}
}
int main()
{
for(int t=read(),Case=1,ans;Case<=t;++Case)
{
n=read(),ans=1,memset(dep+1,0,n<<2),memset(son+1,0,n<<2),std::fill(g,g+n+1,node()),std::fill(pool,now,node()),now=pool;
for(int i=1;i<=n;++i) e[i].clear();
for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
dfs(1,0),alloc(1),dp(1,0);
for(int i=1;i<=n;++i) pushdown(g+i),inc(ans,g[i].val);
printf("Case #%d: %d\n",Case,ans);
}
}
标签:val 时移 main 移动 pool etc type 深度 include
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12498144.html