解:首先看這個純循環究竟是什麼玩意.....c++
通過一番打表,發現純循環小數就是分母與進制互質的既約分數。算法
1 #include <bits/stdc++.h> 2 3 std::bitset<1001> vis; 4 5 inline bool check(int x, int y) { /// x / y 6 //printf("x = %d y = %d \n", x, y); 7 vis.reset(); 8 int rest = x % y; 9 if(!rest) return true; 10 int op = rest; 11 vis[op] = 1; 12 //printf("op = %d \n", op); 13 while(true) { 14 rest *= 10; 15 int r = rest % y; 16 //printf("r = %d \n", r); 17 if(vis[r]) { 18 //printf("return %d = %d \n", r, op); 19 return r == op; 20 } 21 vis[r] = 1; 22 rest = r; 23 } 24 return false; 25 } 26 27 int gcd(int a, int b) { 28 if(!b) return a; 29 return gcd(b, a % b); 30 } 31 32 int main() { 33 34 int n; 35 scanf("%d", &n); 36 37 for(int i = 0; i <= n; i++) { 38 for(int j = 1; j <= n; j++) { 39 if(gcd(i, j) == 1) printf("%d ", (int)check(i, j)); 40 else printf(" "); 41 } 42 puts(""); 43 } 44 45 return 0; 46 }
那麼就有了一個很顯然的O(nmlogV)的作法...直接暴力枚舉而後檢驗。實測24分。ide
1 #include <bits/stdc++.h> 2 3 int gcd(int a, int b) { 4 if(!b) return a; 5 return gcd(b, a % b); 6 } 7 8 int main() { 9 int n, m, k, ans = 0; 10 scanf("%d%d%d", &n, &m, &k); 11 if(1ll * n * m > 1000000000) return 0; 12 for(int i = 1; i <= m; i++) { 13 if(gcd(k, i) > 1) continue; 14 for(int j = 1; j <= n; j++) { 15 ans += gcd(i, j) == 1; 16 } 17 } 18 printf("%d\n", ans); 19 return 0; 20 }
而後發現最裏面那句話有點像phi...仔細思考以後發現不是。spa
如今開始鬼畜時間...推柿子。3d
其中有兩步轉化,分別是把[x=1]用∑μ代替和把[1=(id,k)]用[1=(i,k)][1=(d,k)]代替。rest
因而考慮最後這個式子,發現有個東西[1=(a,k)],因而設這個東西爲g(x),它的前綴和爲f(x)。又令F爲μ·g的前綴和。code
那麼答案就是下式:blog
這個東西顯然能夠分塊一波。後兩項能夠O(1)算,前面的能夠線性預處理。因而咱們有個O(n)的算法。能夠得到84分。get
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 20000010; 5 6 int miu[N], p[N], top, f[N], phi[N], n, m, k, F[N]; 7 bool vis[N]; 8 9 inline void getp(int n) { 10 phi[1] = miu[1] = 1; 11 for(int i = 2; i <= n; i++) { 12 if(!vis[i]) { 13 p[++top] = i; 14 miu[i] = -1; 15 phi[i] = i - 1; 16 } 17 for(int j = 1; j <= top && i * p[j] <= n; j++) { 18 vis[i * p[j]] = 1; 19 if(i % p[j] == 0) { 20 //miu[i * p[j]] = 0; 21 phi[i * p[j]] = phi[i] * p[j]; 22 break; 23 } 24 phi[i * p[j]] = phi[i] * (p[j] - 1); 25 miu[i * p[j]] = -miu[i]; 26 } 27 } 28 return; 29 } 30 31 int gcd(int a, int b) { 32 if(!b) return a; 33 return gcd(b, a % b); 34 } 35 36 inline void prework() { 37 for(int i = 1; i <= k; i++) { 38 f[i] = f[i - 1] + (gcd(i, k) == 1); 39 F[i] = F[i - 1] + (f[i] - f[i - 1]) * miu[i]; 40 } 41 int len = std::min(n, m); 42 for(int i = k + 1; i <= len; i++) { 43 f[i] = f[k] * (i / k) + f[i % k]; 44 F[i] = F[i - 1] + (f[i] - f[i - 1]) * miu[i]; 45 } 46 return; 47 } 48 49 inline int getf(int x) { 50 if(x <= k) return f[x]; 51 return f[k] * (x / k) + f[x % k]; 52 } 53 54 int main() { 55 LL ans = 0; 56 scanf("%d%d%d", &n, &m, &k); 57 if(1ll * n * m < 1e9) { 58 for(int i = 1; i <= m; i++) { 59 if(gcd(k, i) > 1) continue; 60 for(int j = 1; j <= n; j++) { 61 ans += gcd(i, j) == 1; 62 } 63 } 64 printf("%lld\n", ans); 65 return 0; 66 } 67 if(n < N) { 68 getp(n); 69 prework(); 70 int len = std::min(n, m); 71 for(int i = 1, j; i <= len; i = j + 1) { 72 j = std::min(n / (n / i), m / (m / i)); 73 /// [i, j] 74 ans += 1ll * (F[j] - F[i - 1]) * (n / i) * getf(m / i); 75 } 76 printf("%lld\n", ans); 77 } 78 return 0; 79 }
接下來補個k = 2 / 3的部分分。嚴格來講應該能應付k是質數的狀況,然然後面k都是合數....it
推倒過程幾乎跟上面同樣,最後獲得這個東西:
考慮怎麼計算後面那個求和符號。當d和k不互質(d是k的倍數)的時候,答案顯然是0。不然令t = i / d,答案就是與k互質的t個個數。這個東西咱們能夠用maxt - maxt / k來O(1)計算。
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 20000010; 5 6 int miu[N], p[N], top, f[N], phi[N], n, m, k, F[N]; 7 bool vis[N]; 8 9 inline void getp(int n) { 10 phi[1] = miu[1] = 1; 11 for(int i = 2; i <= n; i++) { 12 if(!vis[i]) { 13 p[++top] = i; 14 miu[i] = -1; 15 phi[i] = i - 1; 16 } 17 for(int j = 1; j <= top && i * p[j] <= n; j++) { 18 vis[i * p[j]] = 1; 19 if(i % p[j] == 0) { 20 //miu[i * p[j]] = 0; 21 phi[i * p[j]] = phi[i] * p[j]; 22 break; 23 } 24 phi[i * p[j]] = phi[i] * (p[j] - 1); 25 miu[i * p[j]] = -miu[i]; 26 } 27 } 28 return; 29 } 30 31 int gcd(int a, int b) { 32 if(!b) return a; 33 return gcd(b, a % b); 34 } 35 36 inline int calc(int d) { 37 if((d % k) == 0) { 38 return 0; 39 } 40 d = m / d; 41 return d - d / k; 42 } 43 44 inline void prework() { 45 for(int i = 1; i <= k; i++) { 46 f[i] = f[i - 1] + (gcd(i, k) == 1); 47 F[i] = F[i - 1] + (f[i] - f[i - 1]) * miu[i]; 48 } 49 int len = std::min(n, m); 50 for(int i = k + 1; i <= len; i++) { 51 f[i] = f[k] * (i / k) + f[i % k]; 52 F[i] = F[i - 1] + (f[i] - f[i - 1]) * miu[i]; 53 } 54 return; 55 } 56 57 inline int getf(int x) { 58 if(x <= k) return f[x]; 59 return f[k] * (x / k) + f[x % k]; 60 } 61 62 int main() { 63 LL ans = 0; 64 scanf("%d%d%d", &n, &m, &k); 65 if(1ll * n * m < 1e9) { 66 for(int i = 1; i <= m; i++) { 67 if(gcd(k, i) > 1) continue; 68 for(int j = 1; j <= n; j++) { 69 ans += gcd(i, j) == 1; 70 } 71 } 72 printf("%lld\n", ans); 73 return 0; 74 } 75 if((k == 2 || k == 3) && (n <= 10000)) { 76 getp(n); 77 int len = std::min(n, m); 78 for(int i = 1; i <= len; i++) { 79 ans += 1ll * miu[i] * (n / i) * calc(i); 80 } 81 printf("%lld\n", ans); 82 return 0; 83 } 84 /*if(n < N) { 85 getp(n); 86 prework(); 87 int len = std::min(n, m); 88 for(int i = 1, j; i <= len; i = j + 1) { 89 j = std::min(n / (n / i), m / (m / i)); 90 /// [i, j] 91 ans += 1ll * (F[j] - F[i - 1]) * (n / i) * getf(m / i); 92 } 93 printf("%lld\n", ans); 94 }*/ 95 return 0; 96 }