HDU4903 The only survival(計數神題)

題目鏈接:HDU 4903
題目大意:給出n個點的無向完全圖,確定每一條邊的長度(1~L之間的任意數),使得1到n的最短路是k。輸出方案數對1000000007取模,多組數據(組數<=5)。
題解:聽過一遍沒有懂,自己又琢磨了很長時間稍微懂了一些。
大概是先枚舉1到每個點的最短路dis(優化之後變成枚舉最短路爲某個值的點有多少個),按dis排序後,從dis大的點向dis小的點連邊,滿足:對於任意dis[j] < dis[i]滿足dis[j]+e(j,i)>=dis[i],並且存在dis[j] < dis[i]使得dis[j]+e(j,i)==dis[i],這個可以容斥(就是這個地方有點不大懂),現在還是有一點懵。
先把代碼貼上吧,註釋和詳細題解之後再補。
code(有參考網上大神o(* ̄︶ ̄*)o )

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define mod 1000000007
#define ll long long
using namespace std;
int c[20][20],cnt[20],n,k,L,ans;
void pre()
{
    for (int i=0;i<13;i++) c[i][0]=1;
    for (int i=1;i<13;i++)
     for (int j=1;j<=i;j++)
      c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
inline int ksm(int a,int b)
{
    int num=1;
    for (;b;b>>=1,a=(ll)a*a%mod)
     if (b&1) num=(ll)num*a%mod;
    return num;
}
int solve(int x)
{
    if (!cnt[x]) return 1;    
    int t1=1,t2=1;
    for (int j=0;j<x;j++)      
    {
        if (!cnt[j]) continue;
        if (x-j>L) return 0;   
        t1=t1*(ll)ksm(L-(x-j)+1,cnt[j])%mod;     
        t2=t2*(ll)ksm(L-(x-j),cnt[j])%mod;
    }
    if (x==k+1) return ksm(t1,cnt[x]); 
    t1-=t2; if (t1<0) t1+=mod;
    t1=ksm(t1,cnt[x]);
    return t1;
}
void dfs(int now,int num,int tot)    
{
    if (now==k)     
    {
        for (int i=1;i+tot<=n;i++)    
        {
            int tmp=num*(ll)c[n-tot-1][i-1]%mod;   
            tmp=tmp*(ll)ksm(L,c[i][2])%mod*(ll)ksm(L,c[n-tot-i][2])%mod;       
            cnt[k]=i; cnt[k+1]=n-tot-i;      
            tmp=tmp*(ll)solve(k)%mod*(ll)solve(k+1)%mod;  
            ans=(ans+tmp)%mod;
        }
        return;
    }
    for (int i=0;i+tot<n;i++)      
    {
        cnt[now]=i;
        int tmp=num*(ll)ksm(L,c[i][2])%mod;       
        tmp=tmp*(ll)c[n-tot-1][i]%mod;     
        tmp=tmp*(ll)solve(now)%mod;
        dfs(now+1,tmp,tot+i);
    }
}
int main()
{
    pre(); 
    int t; scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d%d",&n,&k,&L);
        memset(cnt,0,sizeof(cnt));
        cnt[0]=1; ans=0; dfs(1,1,1);
        printf("%d\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章