hdu4906 Our happy ending 状压dp

 
  

枚举有ai<=L的有n个数的数列a,如果存在子集使得子集的数之和为k,则a是一个好数列,求a有多少个
注意到k<=20
假设a的不同子集和分别是s1,s2,...,st,记做集合S
枚举第i个数p = [1,min(l,k)]
每个子集和si+p 会得到新的子集和的集合S'
每个子集和si都加上p: S< dp[i][S+{p}+S'] = sum(dp[i-1][S]);
S+{p}+S' = S | (1<<(p-1)) | ((S< 边界:
dp[0]=1;
dp的大小maxS为(1< 注意情况:
还要再枚举p (min(l,k) ~ max(l,k)),显然这个p不会被选,但也算作一种情况
dp[i][S] += dp[i-1][S]*(l-k)


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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 pii;
typedef vector 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<=0; S--){
                if(dp[S]==0)    continue; //重要优化

                tmp = dp[S];//必须保存,因为next可能等于S
                rep(p,1,l){
                    next = ( S | (1<<(p-1)) | ((S<


你可能感兴趣的:(动态规划)