Mnnu第三場天梯選拔賽
阿新 • • 發佈:2020-10-23
Mnnu第三場天梯選拔賽
A.
原題連結
題目大意
給$n$個數,求出所有數對的最小公倍數的最大公約數
解題思路
我們對於某個數$a_i$,只要看它和區間$[i+1,n]$的每個數的最小公倍數,因為前面的部分會由前面的數和$a_i$去組合,我們不用重複計算。假如要求$a$對$b$、$c$的$lcm$ 的$gcd$ ,$gcd(ab/gcd(a,b),ac/gcd(a,c))$ ,相當於$agcd(b/gcd(a,b),c/gcd(a,c))$, 實際上就是$agcd(b,c)/gcd(a,b,c)$,所以我們可以考慮一手求字尾的gcd,依次轉移。
解題程式碼
#include<bits/stdc++.h> #define int long long #define ios std::ios::sync_with_stdio(false) #define rep(i,a,n) for (int i=a;i<=n;i++) using namespace std; const int N = 2e5 + 10, MOD = 1e9+7, inf = 0x3f3f3f3f; int a[N], g[N]; signed main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; g[n] = a[n]; g[n - 1] = __gcd(a[n], a[n - 1]); int res = a[n] / g[n - 1] * a[n - 1]; for (int i = n - 2; i >= 1; i--){ g[i] = __gcd(g[i + 1], a[i]); res = __gcd(res, a[i] / g[i] * g[i + 1]); } cout << res << '\n'; return 0; }
D.
原題連結
題目大意
解題思路
與該行互質的點會被直接觀察到,計算出第$i$行的互質數的個數,即求尤拉函式,累計求和。
過題程式碼
#include<bits/stdc++.h> #define ios std::ios::sync_with_stdio(false) #define rep(i,a,n) for (int i=a;i<=n;i++) #define per(i,n,a) for (int i=n;i>=a;i--) #define int long long using namespace std; const int N = 2e5 + 10, MOD = 1e9+7, inf = 0x3f3f3f3f; int vis[N],prime[N],phi[N],len,ans; signed main() { int n; cin >> n; if (n == 1) return cout << 0 << '\n',0; for (int i = 2; i <= n; i++){ if (!vis[i]){ prime[++len] = i; phi[i] = i - 1; } for (int j = 1; j <= len; j++) { if (prime[j] * i > n) break; vis[prime[j] * i] = 1; if (i % prime[j] != 0) phi[i * prime[j]] = phi[i] * (prime[j] - 1); else{ phi[i * prime[j]] = phi[i] * prime[j]; break; } } } for (int i = 2; i <= n- 1; i++) ans += phi[i]; cout << ans * 2 + 3 << '\n'; return 0; }
M.
原題連結
題目大意
給出$n$個區間,$q$個查詢區間,問每次查詢時,該查詢區間內有多少個點至少被$k$個區間覆蓋。
解題思路
使用差分陣列+字首和
生成差分陣列:a[l]++ , a[r+1]--
字首和a[i] += a[i-1]
這樣處理之後,a[i] 表示 i 這個數符合多少個區間。
sum[i] 逐個記錄答案,最後$O(1)$查詢答案。
解題程式碼
#include<bits/stdc++.h> #define ios std::ios::sync_with_stdio(false) #define rep(i,a,n) for (int i=a;i<=n;i++) #define per(i,n,a) for (int i=n;i>=a;i--) #define int long long using namespace std; const int N = 2e5 + 10, MOD = 1e9+7, inf = 0x3f3f3f3f; int a[N],sum[N]; signed main() { int m,k,q; cin >> m >> k >> q; for (int i = 1; i <= m; i++){ int l,r; cin >> l >> r; a[l]++, a[r + 1]--; } for (int i = 1; i < N; i++){ a[i] += a[i - 1]; sum[i] = (a[i] >= k? sum[i - 1] + 1 : sum[i - 1]); } while(q--){ int l,r; cin >> l >> r; cout << sum[r] - sum[l - 1] << '\n'; } return 0; }