1. 程式人生 > 實用技巧 >Mnnu第三場天梯選拔賽

Mnnu第三場天梯選拔賽

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;
}