枚举有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<<p
dp[i][S+{p}+S'] = sum(dp[i-1][S]);
S+{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)
注意到k<=20
假设a的不同子集和分别是s1,s2,...,st,记做集合S
枚举第i个数p = [1,min(l,k)]
每个子集和si+p 会得到新的子集和的集合S'
每个子集和si都加上p: S<<p
dp[i][S+{p}+S'] = sum(dp[i-1][S]);
S+{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)
#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;
}