2017 CDQZ 聯訓 Day9 例題 treecnt

-> 題目連接 <-

【題目大意】

給定一棵n個節點的樹,從1到n標號。選擇k個點,你需要選擇一些邊使得這k個點通過選擇的邊聯通,目標是使得選擇的邊數最少。

現需要計算對於所有選擇k個點的情況最小選擇邊數的總和爲多少。

1<=k<=n<=100000

【解題思路】

因爲這道題要求統計所有k個點的選取方案,暴力枚舉肯定不現實,這種情況下一般可以考慮每條邊的貢獻。

樹上的每條邊都是橋,所以當且僅當選取的k個點在某條邊連接的兩個連通塊中都有接點,刪掉這條邊纔是合理而且必要的。考慮補集,當這k個點只存在於在某條邊連接的兩個連通塊中的一箇中,這條邊就不會對答案造成貢獻。

假設這條邊連接的兩個連通塊的大小分別爲siz和N-siz。那麼這條邊的貢獻就爲CknCksizCkNsiz 。把所有邊的貢獻加起來即爲最終答案。

【代碼】

第一次提交之後WA了一大堆點,後來懶得查錯了直接寫了個#define int long long然後再把int main()改成signed main()就AC了。。這真是個好方法

#include<cstdio>
#include<cstdlib>
#include<vector>
#include<algorithm>
using namespace std;
#define int long long
const int maxn=100000+10,MOD=1000000000+7;
typedef long long LLint;
namespace combine{
    int fac[maxn];
    void exgcd(int a,int b,int& x,int& y){
        if(b==0){x=1;y=0;return;}
        int x0,y0;exgcd(b,a%b,x0,y0);
        x=y0;y=x0-a/b*y0;
    }
    int inv(int a,int p=MOD){
        int x,y;exgcd(a,p,x,y);
        return (x%p+p)%p;
    }
    void init(int n){
        fac[0]=1;
        for(int i=1;i<=n;i++){
            fac[i]=(fac[i-1]*i)%MOD;
        }
    }
    LLint C(int n,int m){
        if(n==m || m==0)return 1;
        if(n<m)return 0;
        return ((long long)fac[n]*inv(fac[n-m])%MOD)
        *inv(fac[m])%MOD;
    }
}
namespace tree{
    int fa[maxn],siz[maxn],ans=0,n,k;
    vector<int>G[maxn];
    inline void addedge(int f,int t){
        G[f].push_back(t);
        G[t].push_back(f);
    }
    int dfs(int x,int f){
        #define C combine::C
        fa[x]=f;siz[x]=1;
        for(int i=0;i<G[x].size();i++){
            int u=G[x][i];
            if(u==f)continue;
            int ssiz=dfs(u,x);
            siz[x]+=ssiz;
            ans=((((ans+C(n,k))%MOD-C(ssiz,k))%MOD
            -C(n-ssiz,k))%MOD+MOD)%MOD;
        }
        return siz[x];
        #undef C
    }
}
#include<cctype>
int geti(){
    int ans=0,flag=0;char c=getchar();
    while(!isdigit(c)){flag|=c=='-';c=getchar();}
    while( isdigit(c)){ans=ans*10+c-'0';c=getchar();}
    return flag?-ans:ans;
}
void puti(int x){
    if(x<0)x=-x,putchar('-');
    if(x>9)puti(x/10);   putchar(x%10+'0');
}
signed main(){
    #define n tree::n
    #define k tree::k
    n=geti(),k=geti();
    combine::init(n);
    for(int i=1;i<n;i++){
        int f=geti(),t=geti();
        tree::addedge(f,t);
    }
    tree::dfs(1,-1);
    printf("%d\n",tree::ans);
    #undef n
    #undef k
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章