hihocoder-1546-集合计数
#1546 : 集合计数
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个包含N个整数的集合S={A1, A2, ... AN},以及一个给定的整数K,请计算有多少个S的子集满足其中的最大值与最小值的和小于等于K。
例如对于S={4, 2, 5, 8}以及K=7,满足的条件的子集有以下4个:{2}, {2, 4}, {2, 5}, {2, 4, 5}。
输入
第一行包含两个整数N和K。
第二行包含N个整数A1, A2, ... AN。
对于30%的数据,1 <= N <= 20
对于70%的数据,1 <= N <= 1000
对于100%的数据,1 <= N <= 100000, 0 <= Ai <= 1000000000, 0 <= K <= 2000000000, A1 ~ AN 两两不同。
输出
输出满足条件的子集数目。由于答案可能非常大,你只需要输出答案除以1000000007的余数。
-
样例输入
-
4 7 4 2 5 8
样例输出
-
4
总结:
(1), 详细审题,看清题意!!!! 是集合的最大值 + 最小值 <= K
(2), 经过 sort 之后,双端往里面扫。
假如 刚好到了 num[i] + num[j] <= K , 那么,num[i]一定在集合中,保证这个集合的最小值。所以,剩下的 i + 1, i + 2, ..... j, 是随意在不在这个集合, 则是 2 ^ (j - i) 种集合。
(3),注意 fast_mode 的 取模操作, 同时对 ans 和 b 取模,保证结果 % MOD。
#include <cstdio>
#include <cstdlib>
const int MAXN = 1e5 + 10;
const int MOD = 1000000007;
int num[MAXN];
int cmp(const void *a, const void *b){
return (*(int *)a - *(int *)b);
}
long long fast_mode(long long a, long long b){
long long ans = 1;
while(b > 0){
if(b%2 == 1){
ans = ( ans * a ) % MOD;
}
a = (a*a) % MOD;
b /= 2;
}
return ans;
}
int main(){
int n, k;
long long ans;
while(scanf("%d %d", &n, &k) != EOF){
for(int i=0; i<n; ++i){
scanf("%d", &num[i]);
}
qsort(num, n, sizeof(num[0]), cmp);
ans = 0;
int j = n-1;
for(int i=0; i<n && 2*num[i] <= k; ++i){
while(j>=i && num[j] + num[i] > k){
--j;
}
if(j >= i){
ans = (ans + fast_mode(2, j-i)) % MOD;
}
}
printf("%lld\n", ans );
}
return 0;
}