弄了差不多一下午 东查查西找找终于把题目算是弄懂了...
也不算懂 算是个半懂吧....多刷几道状压DP题就好了。
通过集合枚举每个状态,找到哪个状态是由哪个状态转化而来的(枚举每个状态集合的子集)
如果这个子集集合和某个题目的要求的集合相等那么
那么就让这个状态dp【i】和dp【u】(前置状态dp数组)+做对了题目数量*a【j+1】+b【j+1】相比较
更新最大值
最后枚举每个状态取最大就行了。
/*
qq:1239198605
ctgu_yyf
*/
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=1<<21;
const int inf=0x3f3f3f3f;
ll dp[maxn];
ll qian[maxn],a[maxn],b[maxn];
ll count(ll x)
{
ll num=0;
for(int j=0;j<25;j++)
if(x&(1<<j)) num++;
return num;
}
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%d",&a[i],&b[i],&m);
qian[i]=0;
for(int j=0;j<m;j++)
{
int k;
scanf("%d",&k);
//转换成二进制存储 做出这道题前 要先做哪些题
qian[i]+=(1<<(k-1));
}
}
ll ans=0;
for(int i=0;i<=(1<<n)-1;i++)
dp[i]=-inf;
dp[0]=0;
for(int i=1;i<=(1<<n)-1;i++)
for(int j=0;j<n;j++)
{
if(i&(1<<j))//枚举子集
{
int u=i-(1<<j);
if((u&qian[j+1])==qian[j+1])
{
ll w=dp[u]+count(i)*a[j+1]+b[j+1];
dp[i]=max(dp[i],w);
ans=max(ans,dp[i]);
}
}
}
printf("%lld\n",ans);
return 0;
}