求第n个数
题目描述:
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).
n<=2*10^18,2<=r<=62,T<=30000.
题解:
首先正着想,给出一个n,求出它里面有几个合法的数. 先去掉2, 再去掉3,在加上6…就是这样容斥. 和莫比乌斯函数一样.提供符号. 然后容次来算, 注意. 之后二分合法的x,就是结果.
但是
这道题时间卡的很紧,有下面的优化;
(1)容次大于62的值直接不算.因为只有1,那么我们把一都不算,他们就都是0了,因此容次就大约是60的复杂度.(用莫比乌斯打表也一样)
(2)每次算不二分,而是用迭代. 最终结果x-f(x)=n, 我们写x=n+f(x).先把n当x算n+f(n),这个值一定小于等于x,那么就n+f(ans) 这个值也一定小于等于x,并且一直都是小于等于,并且一直再增加. 于是几次迭代就得到了.
重点:
发现容次直接可以正着算有几个.
容次的优化,去掉1之后很多0.
二分和迭代的学习
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(ll i = a;i < b;i++)
#define REP_D(i, a, b) for(ll i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const ll maxn = 1e9;
ll p[1000];
ll vis[1000];
ll pn;
void getP()
{
CLR(vis);
pn = 0;
for(ll i = 2;i <= 100;i++)
{
if(vis[i]==0)
{
p[pn] = i;
//printf("%d %d\n", pn, p[pn]);
pn++;
for(ll j = i+i;j<=100;j+= i)
{
vis[j] = 1;
}
}
}
}
ll key = 62;
ll ans;
ll r, n;
ll getF(ll x, ll res)
{
if(res==1)
return 0;
ll t;
t = (pow(x, 1.0/(res*1.0))+1e-9);
return t - 1;
}
void calcu(ll x, ll pos, ll res, ll fu)
{
if(res >= key)
return;
if(p[pos] > r)
{
ans += fu*(getF(x, res));
return;
}
calcu(x, pos+1, res*p[pos], -fu);
calcu(x, pos+1, res, fu);
}
ll f_old(ll n)
{
ll l = 1, r = 2*n;
while(r - 1 >= l)
{
ll mid = (l+r)/2;
ans = 0;
calcu(mid, 0, 1, 1);
if(ans >= n)
{
r = mid;
}
else
{
l = mid + 1;
}
}
return r;
}
ll getCha(ll tn)
{
ans = 0;
calcu(tn, 0, 1, -1);
return ans + 1;
}
ll f(ll n)
{
ll out = n + getCha(n);
ll t;
while((t = n+getCha(out)) != out)
{
//printf("%I64d---%I64d\n", getCha(out), getCha(n));
out = n + getCha(t);
}
return out;
}
void solve()
{
printf("%I64d\n", f(n));
}
int main()
{
// freopen("10Jin.txt", "r", stdin);
// freopen("10Jout.txt", "w", stdout);
getP();
int t;
scanf("%d", &t);
while(t--)
{
scanf("%I64d%I64d", &n, &r);
solve();
}
return 0;
}