SPOJ INTSUB - Interesting Subset(数学)
http://www.spoj.com/problems/INTSUB/en/
题意:给定一个集合,该集合由1,2,3....2n组成,n是一个整数。问该集合中有趣子集的数目,答案mod1e9+7。
x的子集合有趣定义为,该子集中至少有两个数,a和b,b是a的倍数且a是集合中最小的元素。
思路:考虑集合中最小的元素a,对于每个a,使得可以构成子集的元素(即b)有beishu = 2 * n / a - 1个,那么这里只考虑这些有2^beishu - 1个。那么还剩下other = 2 * n - beishu - a个比a大的且不是a的倍数的元素,这些元素可以取或者不取,因此有2^other种。两个相乘即可以得到最小元素为a时候的子集数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int MOD = 1000000007; 5 LL biao[2020]; 6 7 int main() { 8 int t; 9 scanf("%d", &t); 10 biao[0] = 1; 11 for(int i = 1; i <= 2000; i++) { 12 biao[i] = biao[i-1] << 1; 13 biao[i] %= MOD; 14 } 15 for(int cas = 1; cas <= t; cas++) { 16 int n; 17 scanf("%d", &n); 18 LL ans = 0; 19 for(int i = 1; i <= n; i++) { 20 int beishu = 2 * n / i - 1; // 是i的倍数的个数 21 int other = 2 * n - beishu - i; // 不是i的倍数并且大于i的个数 22 ans = biao[other] * (biao[beishu] - 1) % MOD + ans; // beishu有选和不选两种,因此是2^beishu种,因为不能全部不选,所以-1,其他的有选不选两种,是2^other 23 ans %= MOD; 24 } 25 printf("Case %d: %lld\n", cas, ans); 26 } 27 return 0; 28 }