首页 > 代码库 > hdu 4906 状压dp
hdu 4906 状压dp
/*ID: neverchanjePROG:LANG: C++11*/#include<vector>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<cstdio>#include<set>#include<queue>#include<map>using namespace std;#define INF 1e9#define maxn#define MOD 1000000007#define rep(i,x,y) for(int i=x;i<=y;i++)#define mset(x) memset(x,0,sizeof(x))typedef long long ll;typedef pair<int,int> pii;typedef vector<int> vi;ll dp[1<<(21)] ,t,n,k,l,d, next, maxS;int main(){// freopen("a.txt","r",stdin);// freopen(".out","w",stdout); cin>>t; while(t--){ cin>>n>>k>>l; mset(dp); d = l>k ? l-k : k-l; l = min(k,l); maxS = (1<<k)-1; dp[0]=1; //dp[0][0]=1; int tmp; rep(i,1,n){ for(int S=maxS; S>=0; S--){ if(dp[S]==0) continue; //重要优化 tmp = dp[S];//必须保存,因为next可能等于S rep(p,1,l){ next = ( S | (1<<(p-1)) | ((S<<p)&maxS) ); dp[ next ] = ( tmp+dp[next] )%MOD; } dp[S] = ( dp[S] + (ll)(tmp*d)%MOD )%MOD; } } ll ans=0; rep(S,0,maxS){ if( S&(1<<(k-1)) ){ ans += dp[S]; ans %= MOD; } } cout<<ans<<endl; } return 0;}/*DESCRIPTION:枚举n个数的数列a,有ai<=L,如果存在子集使得子集的数之和为k,则a是一个好数列注意到k<=20假设a的不同子集和分别是s1,s2,...,st,记做集合S枚举第i个数p (1 ~ min(l,k))每个子集和si+p 会得到新的子集和的集合S‘dp[i][S+{p}+S‘] += dp[i-1][S];(S<<p) = S‘ //每个si都加pS+{p}+S‘ = S | (1<<(p-1)) | ((S<<p)&maxS)边界:dp[0]=1;dp的大小maxS为(1<<k)-1注意情况:还要再枚举p (min(l,k) ~ max(l,k)),显然这个p不会被选,但也算作一种情况dp[i][S] += dp[i-1][S]*(l-k)*/
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。