題意:所有正整數遞增排列,刪掉可以寫成a^b形式的數(a, b 為正整數,2<=b<=r),得到新序列y。
當r=3時,序列為: 2,3,5,6,7,10......
給定n,r,找到y(n)(y中的第n個元素)。
資料範圍:n<=2*10^18,2<=r<=62,t<=30000.
分析:case數很大,n很大,不能暴力解決。第一思路是二分:對於某數x,算出它在y中的位置,二分找到位置等於n的第乙個數。
實際求解時,二分上下界處理不好很容易tle,改用迭代法更為高效。若 pos(x) 的位置小於n,則加上n-pos(n),繼續迭代
如何判斷x在y序列中的位置? 只需考慮指數為質數且指數<= r 的情況。但由於^2 , ^3會重複算,要利用容斥原理得到最終解。
特別的,1一定會被刪去,容斥時暫不考慮1,最終再減去1
原因:2^n級複雜度計算容斥,不需要特別考慮1,但時間複雜度過高;任意乙個集合都包括1,當》=64時,集合中只包含1。將1減去後,這些集合變成空集,不需要考慮。只考慮從<=63的集合就可以。最終把1考慮進去就好。
漲姿勢:
~pow(x,1.0 / i)可計算 x 開 i 次方。x+0.5減小精度誤差
~prime【】用負數,這樣乘積為負時表示有奇數個質因子,便於容斥時判斷加減
~這道題時限很緊張,實現時要注意處處優化。起初是暴力因式分解2~63,然後判斷加計算。這樣會多算很多不符合的情況,看起來影響不大,但實際上由於n和case數很大,很可能會導致tle。 對於不同的r,針對性計算容斥組合,能避免很多不必要的計算。
最優版本: 296ms
#include #include #include #include #include #include #include #include #define clr(x, y) memset(x, y, sizeof x)
using namespace std;
typedef long long ll;
ll n,r;
int prime[30]=;
//用負數,便於容斥時判加減
vector m;
void init()
{//得到<=r的質數的各種組合的乘積
m.clear();
for(int i=0;abs(prime[i])<=r;i++)
{int si=m.size();
for(int j=0;j
hdu 4336 容斥原理
按照解題報告的提示,用容斥原理實現 for int j bg 1 j另解 概率dp,康哥指導的 include include includeusing namespace std double f 1 21 gl 22 int main int i,j,k,n double fz,fm while...
hdu4135 容斥原理
題意 給出a,b,n,求出 a,b 範圍內與n互素的數字的個數。即b範圍內的不與n互素的數減去a範圍內不與n互素的數,把 1,a 1,b 中不與n互素的數分別求出來,再減掉就是和n互素的數了。那麼首先將n分解質因數,因子和因子的倍數可以被除盡,一定不與n互素,把這些數都記下來,篩法求素數即可 然後把...
hdu 4135 容斥原理
剛接觸,有關因子個數的增加不太弄得好,然後看到了這個神奇的遞迴 ac include includeusing namespace std define ll long long ll a,b,ansa,ansb,ans,p 100 up void dfs int n,bool tag,ll num...