题目链接: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);
}
}