zoukankan      html  css  js  c++  java
  • 洛谷P3563 POI Polarization

    这道题有结论啊啊啊

    但是不会证啊qaq

    最小就是尽量让少的点能够相互到达,每层的边都与上一层的边反向

    最大要找到树的重心(这都能写错),然后对于每个子树,尽量让根连出的子树大小等于连到根的子树大小

    也就是尽量取 n/2

    转化成了0/1背包问题

    套路:

    对于 ∑a ≤ n

    observation: 不同的数值不超过 O(√n)

    多重背包,这样有 O(√n log n) 个数字从小到大,有一个数值超过了 2 就合并,这样有 O(√n) 个数字  (二进制优化)

    分治 FFT,但实践中不快(这又是啥啊)

    写这道题主要是练习一下 bitset 优化可行性背包,还有这个套路

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<bitset>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 250100;
    const int INF = 1e9+7;
    
    int n,m;
    ll ans;
    int c[maxn];
    
    bitset<maxn> f;
    
    int h[maxn],size;
    struct E{
        int to,next;
    }e[maxn<<1];
    void add(int u,int v){
        e[++size].to=v;
        e[size].next=h[u];
        h[u]=size;
    }
    
    int rt;
    int sz[maxn],fa[maxn],son[maxn],maxs;
    
    void getroot(int u,int par){
        sz[u]=1; son[u]=0;
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(v==par) continue;
            getroot(v,u);
            sz[u]+=sz[v];
            son[u]=max(son[u],sz[v]);
        }
        son[u]=max(son[u],n-sz[u]);
        if(maxs>son[u]){
            maxs=son[u];
            rt=u;
        }
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;}
    
    int main(){
        memset(h,-1,sizeof(h));
        n=read();
        int u,v;
        for(int i=1;i<n;i++){
            u=read(),v=read();
            add(u,v),add(v,u);
        }
        maxs=INF;
        getroot(1,0);
        getroot(rt,0);
        
        for(int i=1;i<=n;i++) ans+=sz[i]-1;
        
        for(int i=h[rt];i!=-1;i=e[i].next){
            ++c[sz[e[i].to]];
        }
        
        for(int i=1;i<=n;i++){
            while(c[i]>2){
                c[i]-=2; ++c[i<<1];
            }
        }
        
        f[0]=1;
        for(int i=1;i<=n;i++){
            while(c[i]--){
                f|=f<<i;
            }
        }
        
        int x;
        for(x=n>>1;x;x--) if(f[x]) break;
        printf("%d %lld\n",n-1,1ll*x*(n-1-x)+ans);
    
        return 0;
    }
  • 相关阅读:
    我用自己做的图书比价搜索买了一本书
    2.17
    最近的工作
    FireBug的Bug
    2.18
    tecent面试题解答
    .net杂记
    python的round测试
    最近在网上买书的体会
    关于迅雷评论的一个改造html css
  • 原文地址:https://www.cnblogs.com/tuchen/p/10413007.html
Copyright © 2011-2022 走看看