Description
小L有严重的选择困难症。
早上起床后,需要花很长时间决定今天穿什么出门。
假设一共有 k k类物品需要搭配选择,每类物品的个数为 Ai Ai,每个物品有一个喜欢值 Vj Vj,代表小L对这件物品的喜欢程度。
小L想知道,有多少种方案,使得选出来的物品喜欢值之和 >M >M
需要注意,每类物品,至多选择1件,可以不选。
早上起床后,需要花很长时间决定今天穿什么出门。
假设一共有 k k类物品需要搭配选择,每类物品的个数为 Ai Ai,每个物品有一个喜欢值 Vj Vj,代表小L对这件物品的喜欢程度。
小L想知道,有多少种方案,使得选出来的物品喜欢值之和 >M >M
需要注意,每类物品,至多选择1件,可以不选。
Input
多组输入
每组数据第一行输入 k,M(1≤k≤6,1≤M≤108) k,M(1≤k≤6,1≤M≤108),表示有多少类物品
接下来 k k行,每行以 Ai(1≤Ai≤100) Ai(1≤Ai≤100)开头,表示这类物品有多少个,接下来 Ai Ai个数,第 j j个为 Vj(1≤Vj≤108) Vj(1≤Vj≤108),表示小L对这类物品的第 j j个的喜欢值是多少。
每组数据第一行输入 k,M(1≤k≤6,1≤M≤108) k,M(1≤k≤6,1≤M≤108),表示有多少类物品
接下来 k k行,每行以 Ai(1≤Ai≤100) Ai(1≤Ai≤100)开头,表示这类物品有多少个,接下来 Ai Ai个数,第 j j个为 Vj(1≤Vj≤108) Vj(1≤Vj≤108),表示小L对这类物品的第 j j个的喜欢值是多少。
Output
每组输出一行,表示方案数
Sample Input
2 5
3 1 3 4
2 2 3
2 1
2 2 2
2 2 2
Sample Output
3
8
思路:小开始以为是dp 但是实际上,这题不需要dp,因为k比较小,所以我们可以想到折半枚举,然后又因为是求符合某一个范围的值我们可以想到二分,
就是折半枚举和二分查找,我们先算出前半段所有可能,然后在枚举后半段的组合是顺便算出答案
ac代码
#include<cstdio>
#include<algorithm>
#include<map>
#include<iostream>
#include<sstream>
#include<cstring>
using namespace std;
int a[7][105];
int num[101*101*101];
int d[6];
int n;
long long ans;
int k,m;
long long cnt = 0;
void dfs(int deep,int sum)
{
if(deep == 0)
{
num[cnt++] = sum;
return ;
}
for(int i = 0; i <= d[deep-1] ;i++)
{
dfs(deep - 1,sum + a[deep-1][i]);
}
}
void dfs2(int start,int ed ,int sum)
{
if(start > ed)
{//cout<<"sum:"<<sum<<endl;
ans += cnt - (upper_bound(num,num+cnt,m-sum) - num);
// cout<<cnt - (upper_bound(num,num+cnt,m-sum) - num)<<endl;
//cout<<"fsfsa"<<endl;
return ;
}
for(int i = 0;i <= d[start-1];i++)
{
dfs2(start+1,ed,sum + a[start-1][i]);
}
}
int main()
{
while(~scanf("%d%d",&k,&m))
{
ans = 0;
memset(d,0,sizeof(d));
for(int i = 0;i < k;i++)
{
scanf("%d",&n);
d[i] = n;
for(int j = 1; j <= n;j++)
{
scanf("%d",&a[i][j]);
}
}
cnt = 0;
dfs(k/2,0);
sort(num,num+cnt);
//cout<<cnt<<endl;
dfs2(k/2+1,k,0);
cout<<ans<<endl;
}
}