Hdu4903 The only survival
The only survival
Time Limit: 40000/20000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 255 Accepted Submission(s): 120
Problem Description
There is an old country and the king fell in love with a devil. The devil always ask the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.
Something bad actually happen. The devil makes this kingdom's people infected by a disease called lolicon. Lolicon will take away people's life in silence.
Although z*p is died, his friend, y*wan is not a lolicon. Y*wan is the only one in the country who is immune of lolicon, because he like the adult one so much.
As this country is going to hell, y*wan want to save this country from lolicon, so he starts his journey.
You heard about it and want to help y*wan, but y*wan questioned your IQ, and give you a question, so you should solve it to prove your IQ is high enough.
The problem is about counting. How many undirected graphs satisfied the following constraints?
1. This graph is a complete graph of size n.
2. Every edge has integer cost from 1 to L.
3. The cost of the shortest path from 1 to n is k.
Can you solve it?
output the answer modulo 10^9+7
Something bad actually happen. The devil makes this kingdom's people infected by a disease called lolicon. Lolicon will take away people's life in silence.
Although z*p is died, his friend, y*wan is not a lolicon. Y*wan is the only one in the country who is immune of lolicon, because he like the adult one so much.
As this country is going to hell, y*wan want to save this country from lolicon, so he starts his journey.
You heard about it and want to help y*wan, but y*wan questioned your IQ, and give you a question, so you should solve it to prove your IQ is high enough.
The problem is about counting. How many undirected graphs satisfied the following constraints?
1. This graph is a complete graph of size n.
2. Every edge has integer cost from 1 to L.
3. The cost of the shortest path from 1 to n is k.
Can you solve it?
output the answer modulo 10^9+7
Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains 3 integers n,k,L.
T<=5 n,k<=12,L<=10^9.
For each test case, the first line contains 3 integers n,k,L.
T<=5 n,k<=12,L<=10^9.
Output
For each test case, output the answer in one line.
Sample Input
2
3 3 3
4 4 4
Sample Output
8
668
Author
WJMZBMR
Source
题目大意:有一张n个点的无向完全图,第i个点的编号是i,每条边的边权在1到L之间的正整数,问存在多少个图使得1到n的最短路是k。
分析:神题!
一个暴力的做法是枚举所有点到1号点的最短路,记作d[i],如果d[i] == d[j],那么i,j之间的边的权值可以任意选,否则边权不能小于|di-dj|,且必然有一条边使得di + dist[i][j] = dj.只是枚举的复杂度高达13^12,承受不了.
其实我们不需要考虑每个点的最短路具体是什么,只需要考虑数量就可以了.计数题的一个转换思路.那么在dfs的时候枚举每个最短路对应的点有多少个就可以了.然后就是极其琐碎的组合数运算.
需要注意的是起点和终点的最短路都已经确定了.选取i个点的组合数要排除这两个点. 同时可能会有大于k的最短路出现,统统放到k+1处理.关于具体的组合数的运算我写在了代码里:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int mod = 1e9+7; int T; ll n,k,l,cnt[20],ans,c[25][25]; void init() { c[0][0] = 1; for (int i = 1; i <= 20; i++) { c[i][0] = 1; for (int j = 1; j <= 20; j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod; } } ll qpow(ll a,ll b) { ll res = 1; while (b) { if (b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1; } return res; } ll solve(ll x) { if (!cnt[x]) return 1; ll x1 = 1,x2 = 1; for (int i = 0; i < x; i++) { if (!cnt[i]) continue; if (x - i > l) //方案不合法,最短路会被更新 return 0; x1 = (x1 * qpow(l - (x - i) + 1,cnt[i])) % mod; //x1是所有能选的方案 x2 = (x2 * qpow(l - (x - i),cnt[i])) % mod; //x2是所有不合法的方案 } if (x == k + 1) //如果最短路大于k了,那么所有能选的方案都是合法的,因为只是把它们归到k+1这一类,最短路并不一定要等于k+1 return qpow(x1,cnt[x]) % mod; x1 -= x2; if (x1 < 0) x1 += mod; return qpow(x1,cnt[x]) % mod; //之前的方案数都是对于所有的i,1个x来计算的. } void dfs(ll dep,ll fangan,ll tot) //tot传的是1 { if (dep == k) { for (int i = 1; i + tot <= n; i++) { ll temp = fangan * c[n - tot - 1][i - 1] % mod; //剩下的点中选i-1个最短路为k的点,第i个点为终点,不考虑. temp = (temp * qpow(l,c[i][2])) % mod; //这两行就是两两最短路相等的算方案数 temp = (temp * qpow(l,c[n - tot - i][2])) % mod; cnt[k] = i; cnt[k + 1] = n - tot - i; temp = (temp * solve(k)) % mod; temp = (temp * solve(k + 1)) % mod; //最短路大于k的都放到k+1处计算. ans = (ans + temp) % mod; } return; } for (int i = 0; i + tot < n; i++) { cnt[dep] = i; ll temp = fangan * qpow(l,c[i][2]) % mod; //上面说的di == dj的情况,边权随便取 temp = (temp * c[n - tot - 1][i]) % mod; //能选的点中选i个点的方案数 temp = (temp * solve(dep)) % mod; dfs(dep + 1,temp,i + tot); } } int main() { scanf("%d",&T); init(); while (T--) { scanf("%lld%lld%lld",&n,&k,&l); memset(cnt,0,sizeof(cnt)); cnt[0] = 1; //起点被确定了 ans = 0; dfs(1,1,1); printf("%lld\n",ans); } return 0; }