HDU 5297 Y sequence(数论 迭代 容斥原理)

Y sequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 394    Accepted Submission(s): 47


Problem Description
Yellowstar likes integers so much that he listed all positive integers in ascending order,but he hates those numbers which can be written as a^b (a, b are positive integers,2<=b<=r),so he removed them all.Yellowstar calls the sequence that formed by the rest integers“Y sequence”.When r=3,The first few items of it are:
2,3,5,6,7,10......
Given positive integers n and r,you should output Y(n)(the n-th number of Y sequence.It is obvious that Y(1)=2 whatever r is).
 

Input
The first line of the input contains a single number T:the number of test cases.
Then T cases follow, each contains two positive integer n and r described above.
n<=2*10^18,2<=r<=62,T<=30000.
 

Output
For each case,output Y(n).
 

Sample Input
  
  
2 10 2 10 3
 

Sample Output
  
  
13 14
 

题目大意:给出n和r,求数列Y的第n个元素是多少。其中数列Y是正整数数列去除a^b(2<=b<=r)后的数。

例如:n=15,r=5

正整数数列:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ……

当b=2时,去除的数:1   4      9      16      25       36 ……

当b=3时,去除的数:1   8     27     64     125    216 ……

当b=4时,去除的数:1  16    81     256   ……

当b=5时,去除的数:1  32    243  1024  ……

Y数列:2   3   5   6   7   10   11   12   13   14   15   17   18   19   20   21   22   23   24   26   28   29   30   31 ……

  下标:1   2   3   4   5    6     7     8      9    10   11   12   13   14  15   16   17   18   19    20   21   22   23   24 ……

解题思路:本题数据超int(n<=2*10^18,2<=r<=62,T<=30000),若用枚举的方法去除正整数数列中的a^b(2<=b<=r),则会T掉。

        给出一个数n,则1~n以内的正整数必定会有被去除的(假设被去除x1个),则这n个数中只有(n-x1)个数在Y数列中;如果想得到n个数在Y数列中,那么我们至少要在这n个数后面加上x1个数,设n1=n+x1,则在1~n1内的数有多少在Y数列中呢(假设有m个在Y数列中,去除了x2个)如前面所说,在1~n1内的数最多有n个数在Y数列中(即m<=n),此时判断m与n是否相等。如果相等,则Y数列中第n个数为(n+x1);如果不相等,则继续在(n+x1)数后面再加x2个数,继续判断……一直加到某个数M,使得1~M内的数在Y数列中刚好有n个。

       怎么才能很快的求出1~n内有多少个数可以表示为a^b(2<=b<=r)?????

下面简单列出一些a^b(2<=b<=r)的值:

a=       1   2         3          4              5               6               7                 8                   9                  10               11

b=2     1   4         9         16            25             36             49                64                81                100             121  

b=3     1   8         27        64          125           216           343              512              729              1000            1331 

b=4     1  16        81       256         625          1296          2401           4096            6561            10000          14641 

b=5     1   32      243     1024       3125         7776         16807         32768          59049          100000         161051 

b=6     1   64      729     4096      15625       46656       117649       262144        531441        1000000       1771561 

b=7     1  128    2187   16384     78125      279936      823543      2097152      4782969      10000000     19487171 

b=8     1  256    6561   65536    390625    1679616    5764801    16777216    43046721    100000000   214358881 

b=9     1  512  19683  262144  1953125  10077696  40353607  134217728  387420489  1000000000  2357947691 

我们很容易想到依次去除平方数,三次方数,四次方数,五次方数,六次方数,……,r次方数。基本思想是如此,但是我们根据上面列出的值很容易发现:在a^2中出现的数在a^4,a^6,a^8,……中也出现了,在a^3中出现的数在a^6,a^9,……中也出现了………………。这点我们想的可以用容斥原理解决。

代码如下:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#include <limits.h>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-4)
#define inf (1<<28)
#define sqr(x) (x) * (x)
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
//用负数方便计算容斥的符号
int prime[19] = {-2, -3, -5, -7, -11, -13, -17, -19, -23, -29, -31, -37, -41, -43, -47, -53, -59, -61, -67};
vector <int> rongchi; //需要用容斥计算的幂值
//容斥原理
void get_rongchi(int r)
{
    rongchi.clear();
    for(int i = 0; abs(prime[i]) <= r; i++)//枚举幂值为质数的b//
    {
        int temp = rongchi.size();
        for(int j = 0; j < temp; j++)
        {
            if(abs(prime[i]*rongchi[j]) <= 63)
                rongchi.push_back(prime[i]*rongchi[j]);
        }
        rongchi.push_back(prime[i]);
    }
}
//计算1~x的范围内的数有多少存在于Y数列中
long long calculate(long long x)
{
    if(x == 1)
        return 0;
    long long ans = x;
    for(int i = 0; i < rongchi.size(); i++)
    {
        //若a^b=pow(a,b)=x则b=pow(x,1.0/a) ;
        //+0.5为了保证精度;-1是暂时不包含1(因为当a=1时,a^b一定会等于1)
        long long temp = (long long)(pow(x + 0.5, 1.0/abs(rongchi[i]))) - 1;
        //
        if(rongchi[i] < 0)
            ans -= temp;
        else
            ans += temp;
    }
    return ans - 1; //减去刚才没有包含在内的1
}
//迭代法求Y数列的第n个数
long long solve(long long n,int r)
{
    get_rongchi(r);
    long long ans = n;
    while(1)//
    {
        long long temp = calculate(ans);//保留下来的个数
        if(temp == n)
            break;
        ans += n - temp; //每次加上被删去的数的个数
    }
    return ans;
}

int main()
{
    int r,T;
    long long n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%I64d%d", &n, &r);
        printf("%I64d\n",solve(n,r));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值