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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章