您的位置:首页 > 产品设计 > UI/UE

[多校2015.01.1010 容斥+迭代] hdu 5297 Y sequence

2015-07-26 14:59 525 查看
题意:

给你一个n和一个r,求Y序列的第N项是多少。

所谓的Y序列就是,从1开始,去掉能表示成a^b(2<=b<=r)的数,所构成的序列

例如r=2

序列就是:2,3,5,6,7,8,10,11,12,13,14,15,17....

思路:

我们应该能想到需要一个函数fun(x) 求的是1~x内在Y序列里的数有多少个

这个其实不难,我们可以运用容斥原理,通过63以内的素数进行计算,并且最多做三遍,因为2*3*5*7>63

然后就是一个很神奇的方法了,这个方法特别的秒

就是迭代的方法。

假设我们现在要求第N个Y序列的数,先假设第N个数就是N,那么我们求一下fun(N)=tep

tep代表在Y序列里的有tep个数,不在的就有 N-tep个。

这样我们下次就再求 fun(N+(N-tep)) 看看是否等于N,这样不断迭代下去

直到tep==N为止

为什么这样的是对的呢

因为我们每次只加缺少的个数,其实就是假设如果加的这些数都不会被剔除的话,那么就是答案了。

所以不可能加的超过正确答案。

然后由于很明显是非常离散的,因为是次方级别的,所以迭代次数不会多。

代码:

#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"queue"
#include"map"
#include"vector"
#include"string"
#include"cmath"
using namespace std;
#define ll __int64
int ss[]= {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};
ll n;
int r;
int used[22];
ll dfs(int ii,int x,int k,int tep,double kx)
{
    if(x==k)
    {
        return (int)(pow(kx+0.5,1.0/tep)-1); //注意+0.5控制精度!
    }
    if(tep>63) return 0;
    ll ans=0;
    for(int i=ii+1; i<18; i++)
    {
        if(ss[i]>r || tep*ss[i]>63) break;
        if(used[i]==0)
        {
            used[i]=1;
            ans+=dfs(i,x+1,k,tep*ss[i],kx);
            used[i]=0;
        }
    }
    return ans;
}
ll fun(ll x)
{
    ll ans=0;
    for(int i=1; i<5; i++)
    {
        memset(used,0,sizeof(used));
        if(i%2) ans+=dfs(-1,0,i,1,x*1.0);
        else ans-=dfs(-1,0,i,1,x*1.0);
    }
    return x-(ans+1);
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%I64d%d",&n,&r);
        ll ans=n;
        while(1)
        {
            ll tep=fun(ans);
            if(tep==n) break;
            ans+=n-tep;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: