列表

详情


NC25820. 筱玛爱阅读

描述

筱玛是一个热爱阅读的好筱玛,他最喜欢的事情就是去书店买书啦!
一天,他来到一家有本书的书店,筱玛十分快乐,决定把这家店里所有的书全部买下来。
正巧今天店里在搞促销活动,包含若干个促销方案。每个促销方案是由指定的若干本书构成的集合,如果购买了该方案中所有的书,那么其中最便宜的一本书将免费。但是,每本书只能用于一个促销方案。
作为店里的VIP,筱玛会得到个价格标签。筱玛可以给每本书挑选一个价格标签,使得每个价格标签和每本书一一对应。
筱玛想要知道,在合理利用所有促销方案的情况下,买下所有书最小要多少钱。

输入描述

第一行两个数,分别表示书的本数和促销方案的种数。
第二行个整数,表示每个价格标签上的标注的价格。
接下来行,每行第一个数表示该促销方案包含书的数量。接下来个数,表示书的编号。

输出描述

输出一行一个数,表示答案。

示例1

输入:

4 2
2 3 2 4
2 2 3
2 2 4

输出:

8

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 173ms, 内存消耗: 1476K, 提交时间: 2019-07-07 08:52:46

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int vis[1<<15],dp[1<<15],a[20],n,m,k,sum;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		sum+=a[i];
	}
	sort(a+1,a+n+1);
	for(int i=1,s=0,x;i<=m;i++){
		s=0;
		scanf("%d",&k);
		for(int j=1;j<=k;j++){
			scanf("%d",&x);
			s|=1<<(x-1);
		}
		dp[s]=a[n-k+1];
		vis[s]=1;
	}
	for(int sta=1;sta<(1<<n);sta++){
		for(int s=(sta-1)&sta;s;s=(s-1)&sta){
			if(!vis[s]){
				dp[sta]=max(dp[sta],dp[s^sta]);
			}
			else dp[sta]=max(dp[sta],dp[s^sta]+a[n-__builtin_popcount(sta)+1]);
		}
	}
	printf("%d\n",sum-dp[(1<<n)-1]);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 84ms, 内存消耗: 1272K, 提交时间: 2020-08-01 00:29:08

#include<bits/stdc++.h>
using namespace std;

int main()
{
	int i,j,k,s,x,n,m,a[20],DP[33005]={0};
	bool V[33005]={0};
	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++)scanf("%d",&a[i]),s+=a[i];
	sort(a,a+n);
	while(m--)
	{
		scanf("%d",&j),k=0;
		for(i=0;i<j;i++)scanf("%d",&x),x--,k|=1<<x;
		DP[k]=a[n-j],V[k]=1;
	}
	for(i=1;i<(1<<n);i++)
		for(j=i;j;j=(j-1)&i)
		{
			k=i^j,DP[i]=max(DP[i],DP[j]);
			if(V[j])DP[i]=max(DP[i],DP[k]+a[n-__builtin_popcount(i)]);
		}
	printf("%d\n",s-DP[(1<<n)-1]);
    return 0;
}

上一题