hdu5297 Y sequence(容斥原理+迭代)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5297

题意:给定整数n和整数r,在1、2、3、4、5.......的序列中删掉能够开2次方的数,3次方的数,4次方的数,.......r次方的数,剩下的数称为Y序列,求Y序列中第n个数是多少。

分析:对于一个数x,假设求出x在Y序列的位置就好办了。

     先无论序列中的1,假如r=3,能够开2次方的数有4,9,16,25,36,49,64.....

                          能够开3次方的数有8,27,64.......

     我们把能够开2次方的数的个数减掉,再把能够开3次方的数的个数减掉,会发现减多了(把既能够开2次方又能够开3次方的数减了两次),然如把减多了的补回来,就要把能够开6次方的数的个数加回来,这样就能够想到容斥原理:先将全部的2~r的数里面的素数组合起来(那些有1个以上某个同样的因子的数不用考虑,之前肯定会被减掉),然后枚举这些数,看这些数的质因子为奇数和还是偶数个........

     得到x的位置后,開始想到用二分,没想到超时了,,,,,,看了一下别人的思路,用的是迭代...改成迭代就a了。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};
int cnt[100]={19,0,1,1,1,1,2,1,1,1,2,1,2,1,2,2,1,1,2,1,2,2,2,1,2,1,2,1,2,1,3,1,1,2,2,2,2,1,2,2
,2,1,3,1,2,2,2,1,2,1,2,2,2,1,2,2,2,2,2,1,3,1,2,2,1};
long long considrt[6000000],nconsidrt;
void GetConsider(int r)
{
    nconsidrt=0;
    int i,j,sz;
    for(i=0;prime[i]<=r;i++)
    {
        sz=nconsidrt;
        for(j=0;j<sz;j++)
        {
            if(considrt[j]*prime[i]<=63)
                considrt[nconsidrt++]=considrt[j]*prime[i];
        }
        considrt[nconsidrt++]=prime[i];
    }
}

long long cal(long long x)
{
    long long ret(0);
    for(int i=0;i<nconsidrt;i++)
    {
        if(cnt[considrt[i]]&1)
            ret+=(long long)pow(x+0.5,1.0/considrt[i])-1;
        else
            ret-=(long long)pow(x+0.5,1.0/considrt[i])-1;
    }
    return x-ret-1;
}

long long solve(long long n,int r)
{
    GetConsider(r);
    long long ans = n;
    while(1)
    {
        long long temp = cal(ans);
        if(temp == n)
            break;
        ans += n - temp; 
    }
    return ans;
}
int main()
{
    int ncase,r;
    long long n;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%I64d%d",&n,&r);
        printf("%I64d\n",solve(n,r));
    }
    return 0;
}


posted @ 2017-04-20 13:35  zhchoutai  阅读(196)  评论(0编辑  收藏  举报