HDU5779 Tower Defence (BestCoder Round #85 D) 计数dp

分析(官方题解):

一点感想:(这个题是看题解并不是特别会转移,当然写完之后看起来题解说得很清晰,主要是人太弱

                这个题是参考faebdc神的代码写的,说句题外话,很荣幸高中和faebdc巨一个省,虽然本弱渣高中都没搞过oi)

 

              最短路不等于k,所以根本不存在最短路>=k的,因为存在的话,由最短路知识可知,k+1一定是由k更新过来的,矛盾

              所以最短路不等于k,即最短路小于k

              然后就是不管是多校还是bc,都能碰到有关图的计数类的dp问题,比如2016多校1的刚性图,计算连通二分图的数量

              这个题是计算无向图,满足最短路小于k的数量

              这类题对于我来说比较难,看了题解以后可能还好一点,关键是定义状态

              这个题定义的状态是f[i][j][k]很巧妙,在统计的时候可以保证不重不漏,在更新的时候,正好可以像求解最短路一样按距离一层一层更新

              只能说还是太年轻,不能定义出这么好的状态,既方便统计,又方便转移,总得来说还是要努力提高姿势

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef  long long LL;
const int N = 65;
const LL mod = 1e9+7;
int T,n,m;
inline LL up(LL x,LL y){
  x+=y;if(x>=mod)x-=mod;
  return x;
}
LL f[N][N][N],pw2[N*N/2],pw2_1[N],c[N][N];
void init(){
  for(int i=0;i<=60;++i){
    c[i][0]=c[i][i]=1;
    for(int j=1;j<i;++j){
      c[i][j]=up(c[i-1][j-1],c[i-1][j]); 
    }
  }
  pw2_1[0]=pw2[0]=1;
  for(int i=1;i<=1800;++i)
    pw2[i]=pw2[i-1]*2%mod; 
  for(int i=1;i<=60;++i)
    pw2_1[i]=pw2_1[i-1]*2%mod;
  for(int i=0;i<=60;++i)
    pw2_1[i]=up(pw2_1[i],mod-1);
  f[1][0][1]=1;
  for(int i=1;i<=60;++i)
   for(int j=0;j<i;++j)
    for(int k=1;k<=i;++k){
     if(!f[i][j][k])continue;
     LL tmp=f[i][j][k];
     for(int s=1;s+i<=60;++s){
       tmp=tmp*pw2_1[k]%mod;LL val=tmp;
       val=val*pw2[s*(s-1)/2]%mod;
       val=val*c[s+i-1][s]%mod;
       f[s+i][j+1][s]=up(f[s+i][j+1][s],val);
      }
    }
}
void work(){
   scanf("%d%d",&n,&m);LL ret=0;
   for(int i=1;i<=n;++i)
    for(int j=0;j<m;++j)
     for(int k=1;k<=i;++k){
      if(!f[i][j][k])continue;
       LL tmp=f[i][j][k];
       tmp=tmp*c[n-1][n-i]%mod;
       tmp=tmp*pw2[(n-i)*(n-i-1)/2]%mod;
       ret=up(ret,tmp);
     }
  printf("%I64d\n",ret);
}
int main(){ 
  init();
  scanf("%d",&T);
  for(int i=0;i<T;++i)work();
  return 0;
}
View Code

 

posted @ 2016-07-31 14:12  shuguangzw  阅读(187)  评论(0编辑  收藏  举报