bzoj4169: Lmc的游戏
终于有道我会的了。。。
int f[2][maxn],g[2][maxn],tot[maxn];//构造叶子编号时希望最大/小result 先手取子树最小/大的编号的排名
tot是子树中叶子个数
如果希望最大,可以理解为叶子的编号是为了先手取最大时构造,而且要故意去卡取最小
f[0][x]=(∑f[1][y]-1)+1 取最小时可以把每个孩子的前f[1][y]-1个排名放最小的数,那么下一个一定会被选所以+1
f[1][x]=max(f[0][y]+tot[x]-tot[y]) 因为要取最大,假如选择了y转移,其他子树的值可以全部设为比y的子树中的点小,然后再加上选y的排名
g也是同理推理的
g[0][x]=min(g[1][y]),g[1][x]=∑g[0][y]
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int _=1e2; const int maxn=2*1e5+_; struct node { int x,y,next; }a[maxn];int len,last[maxn]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int f[2][maxn],g[2][maxn],tot[maxn];//构造叶子编号时希望最大/小result 先手取子树最小/大的编号的排名 void dfs(int x) { if(last[x]==0){f[0][x]=f[1][x]=g[0][x]=g[1][x]=1;tot[x]=1;return ;} f[0][x]=1; f[1][x]=-(1<<30); g[0][x]=(1<<30); g[1][x]=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; dfs(y); f[0][x]+=f[1][y]-1; f[1][x]=max(f[1][x],f[0][y]-tot[y]); g[0][x]=min(g[0][x],g[1][y]); g[1][x]+=g[0][y]; tot[x]+=tot[y]; } f[1][x]+=tot[x]; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,x,y; scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); ins(x,y); } dfs(1); printf("%d %d\n",f[1][1],g[1][1]); return 0; }
pain and happy in the cruel world.