HDU 5779 BestCoder Round #85 Tower Defence ( dp升级版 )

来源:互联网 发布:python 循环生成字典 编辑:程序博客网 时间:2024/04/30 01:28

Tower Defence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 85    Accepted Submission(s): 50

Problem Description
Little White recently likes playing Tower Defence. She wants to make a map. The map is an undirected graph which has n vertices(graph may not connect).The length of each edge is 1.The shortest distance of vertice 1 to any other vertices is not equal to k.She wants to know how many graphs which satisfy all these conditions.If two vertices is disconnected, the distance between them is infinite.
Input
The first line of input is an integer T(1T10)
For each test case the first line contains two integers n and k(1kn60)
Output
For each testcase , output a line, the answer mod 1,000,000,007
Sample Input
33 24 25 3
Sample Output
628808
Source
BestCoder Round #85
Recommend
wange2014   |   We have carefully selected several similar problems for you:  5775 5774 5773 5772 5771 

题意:小白最近痴迷于玩Tower Defence。他想要自己制作一张地图。地图是一张有n个点的无向图(图可以不连通,没有重边和自环),所有边的长度都为1,满足从1号点到其他任意一个点的最短路都不等于k.小白想知道这样的图有多少个。如果两个顶点不连通,则它们之间的距离为无穷大。

官方题解:
首先最短路不等于k,可以转化成最短路小于k 考虑dp[i][d][j]表示连通块大小为 i,最短路长度为 d,恰好离1距离为d的有j个转移枚举最短路长度为d-1的有k个,那么首先长度为d的只能向长度为d-1的连边,至少连1条,最多连k条的方案,接着考虑距离为d的j个点,内部连的方案,最后考虑i-1个点中选j个点的方案(因为1号点离自己距离为0)。求出dp[i][d][j]后,对答案的贡献为从n-1个点中选i-1个点组成连通块大小为i的方案(因为1号点一定在连通块内),乘上剩下n-i个点内部乱连的方案。复杂度O(n^3*k) 。
(比1005还难很多。。。)

AC代码:
#include<bits/stdc++.h>using namespace std;typedef long long LL;const int N=65;const int mod=1000000007;int dp[N][N][N];int p2[N*N];int pp[N][N];int C[N][N];void init(){for(int i=0; i < N ; i++){C[i][i] = C[i][0] = 1;for(int j = 1 ; j < i; j++){C[i][j] = ( C[i-1][j-1] + C[i-1][j] )%mod;}}p2[0] = 1;for(int i = 1; i < N*N; i++) p2[i] = p2[i-1] * 2 % mod;  for(int i = 0; i < N; i++) { pp[i][0] =1; for(int j = 1; j < N; j++) { pp[i][j]= 1LL * pp[i][j-1] * ( p2[i]-1 ) % mod; } } dp[1][1][1] = 1; for(int i = 2; i < N; i++){ for(int j = i; j < N; j++){ for(int k = 1; k < j; k++) { for(int u=1; u+k <= j; u++) { dp[i][j][k] +=1LL*dp[i-1][j-k][u] *pp[u][k] % mod*p2[k*(k-1)/2] %mod * C[j-1][k]%mod; if(dp[i][j][k] >= mod) dp[i][j][k]-=mod; } } } }}int main(){    init();    int n,k;int t;     scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&k);        int ans=0;        for(int i = 1; i<=k; i++)        {        for(int d = 1; d <= n; d++)        {        for(int j = 1; j <= d; j++)        {        ans+= 1LL*dp[i][d][j]*C[n-1][d-1] % mod * p2[(n-d)*(n-d-1)/2] % mod;        if(ans >= mod) ans -= mod;}} } printf("%d\n",ans);     }    return 0;}  

1 0
原创粉丝点击