Distinct powers (Project Euler 29 加强版)

题目大意:

$2<=a,b<=n$ 求 $a^b$能表示多少不同的正整数。 

原题中n=100,可以直接暴力求解,常见的两种解法是写高精度或者取对数判断相等。 直觉告诉我应该有更加优秀的解法,于是翻了下discuss,找到了一种复杂度介于O(n)和O(nlognlogn)的解法,拿出来分享一下。

 

首先来看一个性质:

对于一个$a$,可以找到最小的$a_0$,使得$a=a_0^k$.

比如$8^4=4^6=2^{12}$ 都是等价的。

 

对于某个$a^b = (a_0^k)^{b}$, 它只可能和某些$a_0^{b_1}$,$(a_0^2)^{b_2}$,$(a_0^3)^{b_3}\ \cdots\ (a_0^{k-1})^{b_{k-1}}$  等价。

我们来看 $a_0^i\ \ (1<=i<k)$ 与 $a_0^k$ 所能表示的那些数会重复。

显然$a_0^{lcm(i,k)}$ $a_0^{2*lcm(i,k)}$ $a_0^{3*lcm(i,k)\ \cdots}$这些都是可以同时被$a_0^i\ \ (1<=i<k)$ 与 $a_0^k$ 表示的。

对应到$a_0^k$的指数分别是 $\frac{lcm(i,k)}{k}$  $2*\frac{lcm(i,k)}{k}$  $3*\frac{lcm(i,k)}{k}\ \cdots$  把这些指数用一个bool数组标记,最后就可以得到以$a_0^k$为基能表示多少个数。 而且这个值和$a_0$的值无关,只和k有关,记为cnt[k],所以可以预处理。

 

最后统计答案。 枚举$a_0(不能表示成另外一个数的幂的数)$把$a_0\ a_0^2\ a_0^3\ \cdots a_0^k$ 一起考虑,对答案的贡献就是cnt[1]+cnt[2]+...cnt[k].

 

具体实现看代码:  实测n=100w 本地运行只要0.2s左右。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cmath>
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 #define N 1000001
 9 #define M 21
10 
11 ll cnt[N];
12 bool flag[N];
13 bool vis[M][N];
14 
15 int gcd(int x,int y)
16 {
17     int tmp;
18     while (y)
19     {
20         tmp=x%y;
21         x=y; y=tmp;
22     }
23     return x;
24 }
25 
26 int lcm(int x,int y){return 1ll*x*y/gcd(x,y);}
27 
28 int main()
29 {
30     //freopen("in.in","r",stdin);
31     //freopen("out.out","w",stdout);
32     
33     int n,m=1; scanf("%d",&n);
34     for (int i=2;i<=n;i<<=1,m++); m--;
35     
36     for (int i=2;i<=m;i++)
37     {
38         for (int j=1;j<i;j++)
39         {
40             int l=lcm(i,j),len1=l/j,len2=l/i;
41             for (int k=1;k*len1<=n;k++) vis[i][k*len2]=true;
42         }
43     }
44     cnt[1]=n-1;
45     for (int i=2;i<=m;i++)
46     {
47         cnt[i]=cnt[i-1];
48         for (int j=2;j<=n;j++) if (!vis[i][j]) cnt[i]++;
49     }
50     
51     ll ans=0;
52     for (int i=2;i<=n;i++)
53     {
54         if (flag[i]) continue;
55         int p=0; ll x=i;
56         do
57         {
58             flag[x]=true;
59             p++; x*=i;
60         }while (x<=n);
61         ans+=cnt[p];
62     }
63     cout<<ans<<endl;
64     return 0;
65 }

 

posted @ 2017-01-27 23:38  lzw4896s  阅读(357)  评论(0编辑  收藏  举报