HDU - 5297:Y sequence (迭代&容斥)
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).
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).
InputThe 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.
OutputFor each case,output Y(n).Sample Input
2 10 2 10 3
Sample Output
13 14
题意:F(x)表示不大于x的而且满足不少a^b形式的个数,求ans,使得F(ans)=N。
思路:我们可以荣容斥的方法求F(x)。 所以可以用二分来得到答案,但是我们可以用二分超时。 所以我们需要用高效的方法。
先假设当前答案是ans,然后求F(ans),如果F(ans)<N,表示还至少缺N-F(ans)个,所以ans=ans+N-F(ans),继续下一次验证,直到F(ans)==N。
这样优于二分的原因是a^b的形式比较离散,所以迭代的次数比较少。
#include<bits/stdc++.h> #define ll long long using namespace std; int prime[19]={-2,-3,-5,-7,-11,-13,-17,-19,-23,-29,-31,-37,-41,-43,-47,-53,-59,-61,-67}; vector<int>p; void getR(int R) { p.clear(); for(int i=0;abs(prime[i])<=R;i++){ int sz=p.size(); for(int j=0;j<sz;j++){ if(abs(prime[i]*p[j])<=63)p.push_back(prime[i]*p[j]); } p.push_back(prime[i]); } } ll cal(ll x) { if(x==1) return 0; ll res=x; for(int i=0;i<p.size();i++){ ll tmp=(ll)pow(x+0.5,1.0/abs(p[i]))-1; if(p[i]<0) res-=tmp; else res+=tmp; } return res-1; } void solve(ll N,int R) { getR(R); ll ans=N; while(1){ ll tmp=cal(ans); if(tmp==N) break; ans+=N-tmp; } printf("%I64d\n",ans); } int main() { int T,R; ll N; scanf("%d",&T); while(T--){ scanf("%I64d%d",&N,&R); solve(N,R); } return 0; }
超时的二分代码:
#include<bits/stdc++.h> #define ll unsigned long long using namespace std; int prime[19]={-2,-3,-5,-7,-11,-13,-17,-19,-23,-29,-31,-37,-41,-43,-47,-53,-59,-61,-67}; vector<int>p; void getR(int R) { p.clear(); for(int i=0;abs(prime[i])<=R;i++){ int sz=p.size(); for(int j=0;j<sz;j++){ if(abs(prime[i]*p[j])<=63)p.push_back(prime[i]*p[j]); } p.push_back(prime[i]); } } ll cal(ll x) { if(x==1) return 0; ll res=x; for(int i=0;i<p.size();i++){ ll tmp=(ll)pow(x+0.5,1.0/abs(p[i]))-1; if(p[i]<0) res-=tmp; else res+=tmp; } return res-1; } void solve(ll N,int RR) { getR(RR); ll L=N,R=L+1500000000,ans; while(L<=R){ ll Mid=(L+R)/2; if(cal(Mid)>=N) ans=Mid,R=Mid-1; else L=Mid+1; } cout<<ans<<endl; } int main() { int T,R; ll N; scanf("%d",&T); while(T--){ cin>>N>>R; solve(N,R); } return 0; }
It is your time to fight!