「THP3考前信心賽」解題報告

寫在前面&總結:

\(LuckyBlock\) 良心出題人!暴力分給了 \(120pts\)html

\(T1\) 貌似是個結論題,最後知道怎麼算了,用前綴和搞了兩下,寫掛了就很草,最後只能靠暴力拿了 \(30pts\)ios

\(T2\) 顯然數論題,可是我不會化簡/kk,不過用前綴和優化了一下暴力 \(40pts\);數組

\(T3\) 依舊暴力,\(O(n^2)\) 可拿 \(40pts\)函數

\(T4\) 部分分 \(5pts\) \(+\) \(lps\) 隨機輸出 \('7'\) \(5pts\);優化

不會打暴力的 \(OIer\) 不是好 \(OIer\) ,不打暴力的都是**(沒錯說的就是CSP2020上的我ui

感受 \(LuckyBlock\) 此次考察的芝士點比較詳細,先粘個題解網址咕着,之後再補spa

T1

T158717 「THP3考前信心賽」A 將來宇宙code

改自 CF1422Chtm

發現能夠當作取出一段序列,把剩下的拼接起來blog

在拼接過程當中發現有許多部分是重複計算的,能夠用後綴和和開個 \(10^i\) 的數組預處理

算了我也說不清楚直接放代碼吧嘻嘻

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long

using namespace std;
const int MAXN = 2e6+6;
const int INF = 1;
const int mod = 1e9+7;

LL hsum[MAXN], jc[MAXN];
char ch[MAXN];
LL ans;

int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
	return s * w;
}

LL quick(LL x, LL p, LL mod){
	LL res = 1;
	for( ; p; p >>= 1){
		if(p & 1) res = res * x % mod;
		x = x * x % mod;
	}
	return res;
}

signed main()
{
	cin>>ch;
	LL len = strlen(ch);
	int cnt = 0;
	cnt = 1; jc[0] = 1;
	for(int i = 1; i <= len; ++i){
		jc[i] = jc[i - 1] * 10 % mod;
	}
	cnt = 0;
	for(int i = len - 1; i >= 0; --i){//求後綴數 
		cnt = (cnt + (ch[i] - '0') * jc[len - 1 - i] % mod) % mod;
		hsum[i] = cnt;
//		cout<<hsum[i]<<' ';
	}
	LL val = 0, sum = 0;
	for(int i = 0; i < len; ++i){
		ans += sum * jc[len - 1 - i] % mod;
		ans += i * hsum[i] % mod;
		ans %= mod;
		val = (10 * val % mod + ch[i] - '0') % mod;
		sum = (sum + val) % mod;
	}
	printf("%lld", ans % mod);
	return 0;
}

暴力部分核心代碼

for(int l = 0; l < len; ++l){
		LL cnt = 0;
		for(int r = l; r < len; ++r){
			for(int i = 0; i < len; ++i){
				if(i < l || i > r){
					cnt = (cnt * 10 % mod + ch[i] - '0') % mod;
				}
			}
			ans = (ans + cnt) % mod;
		}
	}

T2

「THP3考前信心賽」B 空海澄澈

\(40pts\) 暴力:

\(gcd(i, n)\) 是有屢次求的,能夠用前綴和預處理 \(2000\) 個點而後 \(O(n)\) 出結果

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int MAXN = 1e6+6;;
const int INF = 1;
const int mod = 998244353;

int T, l, r;
int gcd[2010][2010];
int sum[2020];

int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
	return s * w;
}

int Gcd(int x, int y){
	return x % y == 0 ? y : Gcd(y, x % y);
}

void init(){
	for(int i = 1; i <= 2000; ++i){
		for(int j = 1; j <= i; ++j){
//			a[i][j] = Gcd(j, i);
			sum[i] = (sum[i] + Gcd(j, i)) % mod ;
		}
	}
}

int main()
{
	init();
	T = read();
	while(T--){
		l = read(), r = read();
		int ans = 0;
		for(int i = l; i <= r; ++i){
			ans = (ans + sum[i]) % mod;
		}
		printf("%d\n", ans);
	}
	return 0;
}

\(100pts\) 正解

考慮化一下 \(f\)

\[f(n) = \sum_{i = 1}^{n} \gcd (i, n) \]

考慮對於每個 \(1 \sim n\) 的值,能做爲多少數對的 \(gcd\) ,因而有:

\[f(n) = \sum_{i = 1}^{n}d\sum_{i = 1}^{n}[gcd(i, n) = d] \]

發現 \(gcd(i, n) = d\) 的必要條件是 \(d \mid n\) ,原式能夠改成:

\[f(n) = \sum_{d \mid n} d \sum_{i = 1}^{n}[gcd(i, n) = d] \]

考慮什麼樣的 \(i\) ,知足 \(\gcd(i, n) = d\) ,顯然當且僅當 \(i = kd(k \in \mathbb{N^*})\) ,且 \(\gcd(k, \frac{n}{d}) = 1\) 是知足條件。爲保證 \(i \le n\) ,有 \(k \le \left\lfloor\frac{n}{d}\right\rfloor\)

因而考慮把 \(d\) 提出來,改成枚舉上述的 \(k\) ,原式等於:

\[f(n) = \sum_{d|n} d \sum_{k=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\left[\gcd\left(k,\frac{n}{d}\right)=1\right] \]

考慮後面一個 \(\sum\) 的實際意義,表示 \(1 \sim \frac{n}{d}\) 中與 \(\frac{n}{d}\) 互質的個數,符合歐拉函數的定義,因而原式等於:

\[f(n) = \sum_{d|n} d \cdot \varphi\left(\frac{n}{d}\right) \]

線性篩預處理 \(\varphi\) 後,有埃氏篩便可篩出 \(1 \sim 10^{6}\) 的全部的 \(f\)

作個前綴和便可回答區間詢問

複雜度 \(O(n\ \log \ n + m)\)

(Solution來自LuckyBlock的題解

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int MAXN = 1e6+5;
const int kMax = 1e6;
const int INF = 1;
const int mod = 998244353;

int p_cnt, p[MAXN], phi[MAXN];
int f[MAXN], sum[MAXN];
bool vis[MAXN];

int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
	return s * w;
}

void init(){
	phi[1] = 1;
	for(int i = 2; i <= kMax; ++i){
		if(!vis[i]){
			p[++p_cnt] = i;
			phi[i] = i - 1;
		}
		for(int j = 1; j <= p_cnt && i * p[j] <= kMax; ++j){
			vis[i * p[j]] = true;
			if(i % p[j] == 0){
				phi[i * p[j]] = phi[i] * p[j];
				break;
			}
			phi[i * p[j]] = phi[i] * (p[j] - 1);
		}
	}
	
	for(int i = 1; i <= kMax; ++i){
		for(int j = i; j <= kMax; j += i){
			f[j] = (f[j] + 1ll * phi[i] * (j / i) % mod) % mod;
		}
	}
	for(int i = 1; i <= kMax; ++i){
		sum[i] = (sum[i - 1] + f[i]) % mod;
	}
}

int main()
{
	init();
	int m = read();
	while(m--){
		int l = read(), r = read();
		printf("%d\n", (sum[r] - sum[l - 1] + mod) % mod);
	}
}

T3

T158720 「THP3考前信心賽」C 舊約酒館

\(40pts\) 暴力:

暴力更改區間起點暴力求全部狀況的最大值便可

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int MAXN = 1;
const int INF = 1;
const int mod = 1;

int n;
char a[50100], b[50010];

int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
	return s * w;
}

int main()
{
	n = read();
	cin>>a>>b;
	int ans = -1;
	for(int i = 0; i < n; ++i){
		int cnt = 0;
		for(int j = 0; j < n; ++j){
			int x = i + j;
			x = (x >= n ? x - n : x);
			if(a[j] == '1' && b[x] == '1'){
				cnt++;
			}
		}
		ans = max(ans, cnt);
	}
	printf("%d", ans);
	return 0;
}

\(100pts\) 正解:

利用 bitset 容器,詳細介紹請看 Oi-Wiki

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<bitset>

using namespace std;
const int MAXN = 1e5+10;
const int INF = 1;
const int mod = 1;

int n, ans;
char s1[MAXN], s2[MAXN];
bitset <MAXN> a, b, c;

int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
	return s * w;
}

void max(int &x, int y){if(x < y) x = y; }

int main()
{
	n = read();
	scanf("%s", s1 + 1);
	scanf("%s", s2 + 1);
	for(int i = 1; i <= n; ++i){
		a[i] = (s1[i] == '1');
		b[i] = (s2[i] == '1');
	}
	for(int i = 1; i <= n; ++i){
		b[n + 1] = b[1];
		b >>= 1;
		max(ans, (a & b).count());
	}
	printf("%d", ans);
	return 0;
}

T4

「THP3考前信心賽」D 博物之志

改自 CF1422C

只拿了部分分就不粘碼了嘻嘻

相關文章
相關標籤/搜索