首先是喜闻乐见的几个入门基础题,连题面基本都是一样的,流程是预处理mu函数,得到输入数据后整除分块(如果时间复杂度需要的话),思路主要是套用下图第二个公式:
(截图来自电科bilibili上的算法讲堂大家可以去看哦)
洛谷2257
题意:全部gcd(1~n,1~m)为质数的个数。
刚开始不用管他要求的数有什么特性,就列一般式子:
(截图来自pengym的博客题解)
但这个题用第二条推出的式子还得变一变,就直观感受去变!d的范围?n是质数?把F(d)提出去?
下图中T即为上图中的d,t即为n。
式子写到这里就可以写代码了,先把mu全加上,这样写:
1 rep(j, 1, cnt) { 2 for (int i = 1; i * primes[j] <= n; i++) { 3 g[primes[j] * i] += mu[i]; 4 } 5 }
然后整除分块是某一块乘上的(n/T)*(m/T)是不变的,所以这一块一起算,代码是这样的:
1 rep(i, 1, n) sum[i] = sum[i-1] + g[I];//这个是预处理
1 ll ans = 0ll; 2 for (int l = 1, r; l <= n; l = r + 1) { 3 r = min(n / (n / l), m / (m / l)); 4 ans += (sum[r] - sum[l - 1]) * (n / l) * (m / l); 5 }
总代码(部分):
1 void pre(int n) { 2 mu[1] = 1; 3 rep(i, 2, n) { 4 if (!vis[i]) { 5 mu[i] = -1; 6 primes[++cnt] = i; 7 } 8 for (int j = 1; j <= cnt && primes[j] * i <= n; j++) { 9 vis[primes[j] * i] = true; 10 if (i % primes[j] == 0) break; 11 mu[primes[j] * i] = -mu[i]; 12 } 13 } 14 15 rep(j, 1, cnt) { 16 for (int i = 1; i * primes[j] <= n; i++) { 17 g[primes[j] * i] += mu[i]; 18 } 19 } 20 rep(i, 1, n) sum[i] = sum[i-1] + g[i]; 21 } 22 23 int main() { 24 pre(maxn); 25 for (T = ri; T; T--) { 26 n = ri, m = ri; 27 if (n > m) swap(n, m); 28 29 ll ans = 0ll; 30 for (int l = 1, r; l <= n; l = r + 1) { 31 r = min(n / (n / l), m / (m / l)); 32 ans += (sum[r] - sum[l - 1]) * (n / l) * (m / l); 33 } 34 printf("%lld\n", ans); 35 } 36 return 0; 37 }
HDU1695
(复习一下式子)
题意:gcd(1~b,1~d)== k的个数。
跟上一题很像,甚至这道题根本不用整除分块,也不用进一步推式子……就是求f(k),直接拿第二个式子扫一遍加和就行了。另外去个重,本题(x,y)和(y,x)算一种。
1 void pre(int n) { 2 mu[1] = 1; 3 rep(i, 2, n) { 4 if (!vis[i]) { 5 primes[++cnt] = i; 6 mu[i] = -1; 7 } 8 for (int j = 1; j <= cnt && primes[j] * i <= n; j++) { 9 vis[primes[j] * i] = true; 10 if (i % primes[j] == 0) break; 11 mu[primes[j] * i] = -mu[i]; 12 } 13 } 14 } 15 16 ll cal(int b, int d) { 17 ll ret = 0ll; 18 for (int i = 1; i * k <= b; i++) { 19 int t = i * k; 20 ret += (ll)mu[i] * (b / t) * (d / t); 21 } 22 return ret; 23 } 24 25 int main() { 26 pre(maxn - 5); 27 for (int T = ri, i = 1; i <= T; i++) { 28 a = ri, b = ri, c = ri, d = ri, k = ri; 29 if (b > d) swap(b, d); 30 printf("Case %d: %lld\n", i, k ? cal(b, d) - cal(b, b) / 2 : 0); 31 } 32 return 0; 33 }
BZOJ1101
n次询问gcd(1~a, 1~b) == d。同一道题。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 5e4 + 5; 56 int n, a, b, d; 57 int mu[maxn], primes[maxn], tot, sum[maxn]; 58 bool vis[maxn]; 59 60 void pre(int n) { 61 mu[1] = 1; 62 rep(i, 2, n) { 63 if (!vis[i]) { 64 primes[++tot] = i; 65 mu[i] = -1; 66 } 67 for (int j = 1; j <= tot && primes[j] * i <= n; j++) { 68 vis[primes[j] * i] = true; 69 if (i % primes[j] == 0) break; 70 mu[primes[j] * i] = - mu[i]; 71 } 72 } 73 rep(i, 1, n) sum[i] = sum[i - 1] + mu[i]; 74 } 75 76 ll solve(int n, int m) { 77 if (n > m) swap(n, m); 78 ll ret = 0ll; 79 for (int l = 1, r; l <= n; l = r + 1) { 80 r = min(n / (n / l), m / (m / l)); 81 ret += (ll)(sum[r] - sum[l - 1]) * (n / l) * (m / l); 82 } 83 return ret; 84 } 85 86 int main() { 87 pre(maxn - 5); 88 for (read(n); n; n--) { 89 read(a), read(b), read(d); 90 writeln(solve(a / d, b / d)); 91 } 92 return 0; 93 }