题目链接:https://nanti.jisuanke.com/t/31720
题意:有n种飞船,每种飞船有(1 << c)- 1 艘,容量为 k[i] ,q 次询问,每次询问选若干艘飞船使得容量为 s 的方案数。
题解:预处理出全部情况。dp[ i ][ j ]表示选前 i 个物品凑出容量为 k 的方案数,转移的时候可注意到dp[ i ][ j ] = sigma(dp[i - 1][j - x * v ]),然后减掉不合法的情况(x > ( (1 << c) - 1) )。详见代码~
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define LL __int128 5 #define ull unsigned long long 6 #define mst(a,b) memset((a),(b),sizeof(a)) 7 #define mp(a,b) make_pair(a,b) 8 #define fi first 9 #define se second 10 #define pi acos(-1) 11 #define pii pair<int,int> 12 #define pb push_back 13 const int INF = 0x3f3f3f3f; 14 const double eps = 1e-6; 15 const int MAXN = 1e4 + 10; 16 const int MAXM = 1e6 + 10; 17 const ll mod = 1e9 + 7; 18 19 ll dp[22][MAXN]; 20 21 int main() 22 { 23 #ifdef local 24 freopen("data.txt", "r", stdin); 25 // freopen("data.txt", "w", stdout); 26 #endif 27 int t; 28 scanf("%d",&t); 29 while(t--) { 30 int n,q; 31 scanf("%d%d",&n,&q); 32 mst(dp, 0); 33 dp[0][0] = 1; 34 for(int i = 1; i <= n; i++) { 35 int c,v; 36 scanf("%d%d",&v,&c); 37 c = (1 << c) * v; 38 for(int j = 0; j < v; j++) dp[i][j] = dp[i - 1][j]; 39 for(int j = v; j <= 10000; j++) { 40 dp[i - 1][j] += dp[i - 1][j - v]; 41 if(dp[i - 1][j] >= mod) dp[i - 1][j] -= mod; 42 dp[i][j] = dp[i - 1][j]; 43 if(j >= c) { 44 dp[i][j] -= dp[i - 1][j - c]; 45 if(dp[i][j] < 0) dp[i][j] += mod; 46 } 47 } 48 } 49 while(q--) { 50 int s; 51 scanf("%d",&s); 52 printf("%lld\n",dp[n][s]); 53 } 54 } 55 return 0; 56 }
原文地址:https://www.cnblogs.com/scaulok/p/9653050.html
时间: 2024-11-13 10:20:04