首页 > 代码库 > 2014百度之星初赛(第二场)——JZP Set
2014百度之星初赛(第二场)——JZP Set
2014百度之星初赛(第二场)——JZP Set
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
Source
2014年百度之星程序设计大赛 - 初赛(第二轮)
思路:
考虑到n高达10^7,而T也不小,选择递推预处理出所有答案。
观察(x+y)/2,对集合里的每个数都有这种规律的话,能想到类似的东西就是等差数列。
令ans[i]代表集合[1..i]的JZP子集(空集也算的),那么有ans[i] = ans[i - 1] + count(包含i的[1..i]的JZP子集)。
那么令p[i] = 包含i的[1..i]的JZP子集个数。考虑包含i的等差数列,可以发现等差一定为奇数(偶数都无法构成JZP集合,手动试一下就能发现了)。
例如:{2,4,6}不符合;{1,3,5}也不符合;
首先p[i]有只包含一个数的{i}。
之后对于元素个数大于等于2的,等差为1的子集个数为(i-1)/1,等差为3的子集个数为(i-1)/3……
然后对于元素个数大于等于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的倍数;例如12/3=4;11/3=3;
可以得出p[i]比p[i-1]要大count(i-1的奇数约数)。
对于每个数的约数个数,可以在O(nlogn)的时间里预处理出来(参考素数的筛法)。
然后递推ans[i] = ans[i - 1] + p[i],至此题目完美解决!
以上分析来自博文:http://www.cnblogs.com/oyking/p/3751608.htmlAC代码:
#include<cstdio> #include<algorithm> #define LL long long #define MAX 10000005 using namespace std; LL ans[MAX]; LL Count[MAX]; void GetOddNum()//计算奇约数的个数 { for(int i=1;i<=MAX;i+=2) { for(int j=i;j<=MAX;j+=i) Count[j]++; } } void Init() { ans[0]=1; ans[1]=2; LL cnt=1; for(int i=2;i<MAX;i++) { cnt+=Count[i-1]; ans[i]=ans[i-1]+cnt; } } int main(int argc,char *argv[]) { GetOddNum(); Init(); int t; int n; scanf("%d",&t); for(int i=1;i<=t;i++) { scanf("%d",&n); printf("Case #%d:\n%I64d\n",i,ans[n]); } }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。