input
本題有多組測試資料,每組包含乙個整數n,1<=n<=1000000000000000000(10^18).
output
對於每組輸入,請輸出在在1到n之間形式如m^k的數的總數。
每組輸出佔一行。
sample input
10
361000000000000000000
sample output
4
91001003332
哎,一開始學容斥,並不知道怎麼用上去,**寫起來好寫,但是思路難啊。
下面開始分析:
題目意思:給你乙個n,求出1-n裡面,構成m^k(k>1)的數,比如1-4裡面有1,4兩個,1一定可以。
然後我們就去看資料範圍了,1e18,很大,不可能列舉。
接著我就想,能不能分一下類,按2^k, 3^k, 4^k.......,這種,但是一想,1e18開方也還有1e9,這樣分類不行
隨後我就按照指數來分類,指數相同歸為一類,例如(2^2, 3^2, 4^2....)歸為一類,(2^3, 3^3, 4^3)歸為一類,一次類推。
而且,這樣分類還可以算出這一類有多少個數, 直接乙個公式就行了,就是開k次方,然後-1,因為是從2開始的
某一類的個數
其實這個特別好推。
重要的是下面的:去重
我們分析一下,如果不去重,只需要一直開方,直到不能開為止,然後答案累加,這樣複雜度並不高,1e18次最多開60次方就沒了,因為2^60=1e18,所以時間根本不用擔心。
那麼怎麼去重呢,拿樣例36來說,我們先列舉出來
指數為2:2^2 3^2 4^2 5^2 6^2
指數為3:2^3 3^3
指數為4:2^4
指數為5:2^5
後面就沒了
我們可以看到16這個數重複了,4^2 = 16, 2^4 = 16
這是因為指數4本來就是2的倍數,2^4 = ( 2^2 )^2
那如果我們指數只列舉質數,是不是就能避免這種情況了,而且又可以減小計算量
但是,稍微再列舉一下,又能發現問題,
像 27^2這種 27^2 = ( 3*3*3 )^2 = 3^(3*2) = 3^6 = 9^3
你雖然避免了3^6,但是還有9^3會重複。
這時候就是最難點了,需要用到容斥,個人感覺在這個最後一點上不好想
27^2 和 9^3之所以會重複,是因為它們都有乙個6,就是都能湊出指數6,那麼我們減去指數6所得到的個數,就是答案了。
再自己乙個樣例
n = 729
729 = 27^2 = 3^6
指數為2:2^2 3^2 4^2 5^2 6^2 7^2 8^2 9^2............................27^2
指數為3:2^3 3^3 4^3 5^3 6^3 7^3 8^3 9^3
指數為5:2^5
指數為7:2^7
後面沒有了
這裡,我們就挑指數為2和指數為3的兩類進行分析,看如何去除重複
我們首先要知道,指數為2和3的,重複的數一定可以構成指數為6的數
有 8^2 和 4^3是重複的
然後我們用n算出指數為6的個數,是1個,那麼在算指數為2和3時,先+指數為2的,在+指數為3的,最後--指數為6的,這就用到了容斥原理。
所以我們開始設計演算法:
①首先,我們把n的質指數求出來,質指數就是指數為質數,乙個迴圈就可以搞定,而且非常快,幾下就沒了,前面分析過,就是一直開方,開到不能開為止,那麼我們就把指數記錄了下來。
②指數記錄下來了,就要用容斥了,個人習慣用dfs,簡潔一些,這時候我們還需要設計乙個函式,給你乙個指數值,你能算出這個符合這個指數的答案有多少個
需要注意一點,如果用dfs寫,需要加乙個條件,就是因子乘積小於60,不然就會超時,因為乙個很大的數得出來的指數還是挺多的,指數組合在一起也挺多,但是很多組合都沒有用,因為2^60 > 1e18,或者你加乙個條件,因子最多選3個,不能選多了
#include#include#include#include#include#include#include#include#include#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define mem(a,val) memset(a,val,sizeof a)
#define inf 0x3f3f3f3f
#define longinf 0x3f3f3f3f3f3f3f3f
using namespace std;
#define eps 1e-7
typedef long long ll;
const int maxn = 1e3+4;
bool isprime[maxn];
double prime[maxn];
int primecnt;
double n;
ll ans;
ll a[maxn];
int cnt;
void getprime()
ll f( double x )
void dfs( int start,int times,int goal,double val )
for( int i = start ; i < cnt ; i++ )
dfs(i+1,times+1,goal,val*a[i]);
}int main()
fori(1,cnt-1)
dfs(1,0,i,1);
printf("%lld\n",ans+1);
}return 0;}/*
16 4
2 5 6 9
19 3
2 3 4
*/
hdu 2204 容斥原理
感覺斷斷續續的看了好久的容斥 然後還是看不懂莫比烏斯反演 以後基本原理懂了就先上手做題吧,不然感覺還是不會還浪費時間 第一題容斥 題意 給你乙個數n 1,10 18 叫你求n內有多少個數是m k得來的。可知 m k都可以變成乙個冪數為素數的形式,所以可以列舉素數,求每個素數滿足的個數。因為存在 形如...
HDU 2204(容斥原理)
input 本題有多組測試資料,每組包含乙個整數n,1 n 1000000000000000000 10 18 output 對於每組輸入,請輸出在在1到n之間形式如m k的數的總數。每組輸出佔一行。sample input 10 361000000000000000000 sample outpu...
hdu2204 容斥原理)
容斥原理 設a ia i ai 為集合,ai a i ai 為集合大小 則 a1 a2 a3 a 4 an a 1 cup a 2 cup a 3 cup a 4 cdots a n a1 a 2 a 3 a 4 a n i 1n ai i 1 n j i 1n ai aj i 1 n j i 1n...