Problem Description
一个{1, ..., n}的子集S被称为JZP集,当且仅当对于任意S中的两个数x,y,若(x+y)/2为整数,那么(x+y)/2也属于S。
例如,n=3,S={1,3}不是JZP集,因为(1+3)/2=2不属于S。但是{1,2,3}的其他子集都属于S,所以n=3时有7个JZP集
给定n,求JZP集的个数。
例如,n=3,S={1,3}不是JZP集,因为(1+3)/2=2不属于S。但是{1,2,3}的其他子集都属于S,所以n=3时有7个JZP集
给定n,求JZP集的个数。
Input
第一行为T,表示输入数据组数。
每组数据包含一行整数n。
限制条件
1<=T<=10^5
1<=n<=10^7
每组数据包含一行整数n。
限制条件
1<=T<=10^5
1<=n<=10^7
Output
对第i组数据,输出
Case #i:
然后输出JZP集的个数。
Case #i:
然后输出JZP集的个数。
Sample Input
3 1 2 3
Sample Output
Case #1: 2 Case #2: 4 Case #3: 7
百度之星的初赛最后一题。
这题在比赛的时候没能弄出来。开始经过推到,发现a【n】=a【n-1】+cnt;始终不知道这个cnt怎么得到;
经过手动推到会发现这个集合的数只有一个数的时候满足,当这里面的数字是出现等差数列的时候同样满足,而等差数列的公差一定为奇数。这是当是相当的,那么以后的工作就稍微简单一点了,这就需要求出cnt。具体求发参照大神的题解:
http://www.cnblogs.com/oyking/p/3751608.html
那么令p[i] = 包含i的[1..i]的JZP子集个数。考虑包含i的等差数列,可以发现等差一定为奇数(偶数都无法构成JZP集合,手动试一下就能发现了)。
首先p[i]有只包含一个数的{i}。
之后对于元素个数大于等于2的,等差为1的子集个数为(i-1)/1,等差为3的子集个数为(i-1)/3……
但是这还不能满足题目的要求。
考虑p[i]-1和p[i-1]-1的区别,对于(i-1)/1+(i-1)/3+(i-1)/5……和(i-2)/1+(i-2)/3+(i-2)/5……,对于分母为x的,(i-1) / x > (i-2) / x当且仅当(i-1)是x的倍数
可以得出p[i]比p[i-1]要大count(i-1的奇数约数)。
对于每个数的约数个数,可以在O(nlogn)的时间里预处理出来(参考素数的筛法)。
然后递推ans[i] = ans[i - 1] + p[i],至此题目完美解决!
#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<sstream>
#include<cassert>
using namespace std;
#define LL __int64
//#define LL long long
#define maxn 10000007
int n;
LL a[maxn];
LL p[maxn];
void init() {
for(int i=1; i<=maxn; i+=2) {
for(int j=i; j<=maxn; j+=i) {
p[j]++;
}
}
a[1]=2;
LL sum=0;
for(int i=2; i<maxn; i++) {
sum+=p[i-1];
a[i]=a[i-1]+sum+1;
}
}
int main() {
int t;
memset(p,0,sizeof(p));
init();
cin>>t;
for(int ii=1; ii<=t; ii++) {
scanf("%d",&n);
printf("Case #%d:\n",ii);
printf("%I64d\n",a[n]);
}
return 0;
}