• BZOJ3425 : Poi2013 Polarization


    最小值肯定是把树看作二分图,此时答案为$n-1$。

    最大值一定是选取重心为根,任意一个子树要么全部指向根,要么全部背离根,这样可以制造最大的星型图。

    统计出每个子树的大小后做01背包,如果小于$sqrt{n}$,那么二进制拆分,否则这种子树不超过$sqrt{n}$个,直接DP即可。

    用bitset优化转移,时间复杂度$O(frac{nsqrt{n}}{32})$。

    #include<cstdio>
    #include<bitset>
    #include<algorithm>
    #define N 250010
    using namespace std;
    int n,m,i,j,k,x,y,g[N],v[N<<1],nxt[N<<1],ed,son[N],f[N],S,cnt[N],q[N],t;
    bitset<N>dp;long long ans,sum;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void findroot(int x,int y){
      son[x]=1;
      for(int i=g[x];i;i=nxt[i])if(v[i]!=y){
        findroot(v[i],x);
        son[x]+=son[v[i]];
        if(son[v[i]]>f[x])f[x]=son[v[i]];
      }
      if(n-son[x]>f[x])f[x]=n-son[x];
      if(f[x]<f[S]||!S)S=x;
    }
    void dfs(int x,int y){
      son[x]=1;
      for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x),son[x]+=son[v[i]];
      if(y==S)if(son[x]<=m)cnt[son[x]]++;else q[++t]=son[x];
      sum+=son[x]-1;
    }
    int main(){
      read(n);
      for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
      findroot(1,0);
      while(m*m<n)m++;
      dfs(S,0);
      dp[0]=1;
      while(t)dp|=dp<<q[t--];
      for(i=1;i<=m;i++)for(j=cnt[i],k=1;j;j-=k,k<<=1){
        if(j<=k){dp|=dp<<i*j;break;}
        dp|=dp<<i*k;
      }
      for(i=0;i<n;i++)if(dp[i])ans=max(ans,1LL*i*(n-i-1));
      return printf("%d %lld",n-1,ans+sum),0;
    }
    

      

  • 相关阅读:
    doker基础用法
    docker容器技术基础入门
    流模式
    装饰器模式
    适配器模式
    组合模式
    桥接模式
    观察者模式
    注册模式
    模板模式
  • 原文地址:https://www.cnblogs.com/clrs97/p/5289359.html
Copyright © 2020-2023  润新知