大水题..先介绍下第一种做法dp观察数据易知..每个数大概就是0~100之间,然后最多100组,所以建立一个dp数组dp[i][j]表示到第i组,价值为j的数量是多少?
然后转移就更简单了,思想就是桶,你这个转态肯定是有上一个转态+a[i][j]组成a[i][j]表示第i组位于j的价值..然后注意把第一组初始化为1..
所以转移方程就是:
dp[i][k+a[i][j]]+=dp[i-1][k];
最后从1开始找到10000找k个数就好了..时间复杂度大概1e8吧..
AC代码
#include<bits/stdc++.h> #define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0) #define pb push_back #define inf 132913423039 typedef long long ll; const ll mod=1e9+7; const ll N=1e5+5; const int max_=1e5+5; const double eps=1e-7; using namespace std; ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);} ll lcm(ll a,ll b) { return a*b/gcd(a,b); } ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a = (a*a)%p;b >>= 1;}return ans%p;} ll Inv(ll x) { return qp(x,mod-2,mod);} ll C(ll n,ll m){if (m>n) return 0;ll ans = 1;for (int i = 1; i <= m; ++i) ans=ans*Inv(i)%mod*(n-i+1)%mod;return ans%mod;} ll dp[105][105*105];//dp[i][j]到第i组,价值为j的数量是多少? ll a[105][105]; ll cnt[105]; int main() { ios; ll n,m,ans=0; cin>>n>>m; for(ll i=1;i<=n;i++) { cin>>cnt[i]; for(ll j=1;j<=cnt[i];j++) cin>>a[i][j]; } for(ll i=1;i<=cnt[1];i++) dp[1][a[1][i]]=1;//赋初值 for(ll i=2;i<=n;i++)//3个for复杂度大概1e8吧 { for(ll j=1;j<=cnt[i];j++) { for(ll k=1;k<=10000;k++) { if(k+a[i][j]<=10000)//选了就+ai嘛 { dp[i][k+a[i][j]]+=dp[i-1][k]; } } } } for(;m;)//挑选前m小的数嘛~ { for(ll i=1;i<=10000;i++) { if(dp[n][i]) { if(m-dp[n][i]>=0) m-=dp[n][i],ans+=dp[n][i]*i; else ans+=m*i,m=0; } if(m==0) break; } } cout<<ans<<endl; return 0; }
2.dp可以优化的..但是这是思路最简单的一种了