大水题..先介绍下第一种做法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可以优化的..但是这是思路最简单的一种了

京公网安备 11010502036488号