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; }