比赛链接:

https://pintia.cn/problem-sets/1574060137151397888

A.Yet Another Remainder

题意:

给定一个大数 \(x\),长为 \(n\),已知 \(m(m = min(100, n))\) 行,第 \(i\) 行第 \(j\) 个数表示大数的第 \(j\) 位开始以步长为 \(i\) 的选法,选出的数的和,现在有 \(q\) 次询问,每个给定质数 \(p\),输出大数 mod \(p\) 是多少。

思路:

由费马小定理可得 \(x^{p - 1} \equiv 1(mod p)\),大数的每一位要乘上一个 \(10^i\),如果按照长为 \(p\) 的循环节进行分组,每一组的 \(10^i mod p\) 是相同的,且每一组的和就是 \(b[p - 1][i](i = 10^i mod p)\),就是题目给出的条件。\(10^i mod p\) 的数组可以预处理。
\(n <= p - 1\) 的情况就解决了。
\(n > p - 1\),因为 \(p <= 97\),那么大数的每一位已知了,即 \(b[n][j]\),直接暴力求即可。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 110;
int b[N][N], fac[N];
void solve(){
	int n;
	cin >> n;
	for (int i = 1; i <= min(n, 100); i ++ )
		for (int j = 1; j <= i; j ++ )
			cin >> b[i][j];
	int q;
	cin >> q;
	while(q -- ){
		int p, ans = 0;
		cin >> p;
		if (p - 1 <= n){
			fac[0] = 1;
			for (int i = 1; i <= p - 1; i ++ )
				fac[i] = fac[i - 1] * 10 % p;
			for (int i = 1; i <= p - 1; i ++ )
				ans = (ans + b[p - 1][i] * fac[(n - i) % (p - 1)]) % p;
		}
		else{
			for (int i = 1; i <= n; i ++ )
				ans = (ans * 10 + b[n][i]) % p;
		}
		cout << ans << "\n";
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

B.Non-decreasing Array

题意:

长为 \(n\) 的非递减序列 \(a\),当当前序列的长度为 \(m\) 时,每次操作可以先选择(也可以不选)一个元素 \(a_i(1 < i < m)\) 然后删除它,接着再选一个数 \(a_i(1 < i < m)\),将它变成任何一个数,但要保证序列还是非递减的,现在可以进行 \(k(1 <= k <= n)\) 次操作,问操作之后 \(\sum_{i = 2}^{m} (a_i - a_{i - 1})\) 的最大值是多少,对于每个 \(k\) 答案是独立的。

思路:

对于一个序列,最后剩下的肯定是两边的值,定义 \(dp[i][j]\) 表示保存第 \(i\) 位和第 1 位,然后删除了 \(j\) 个元素的最大值。
从小到大开始枚举删除了几个数,求答案即可。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 110;
LL a[N], dp[N][N];
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i ++ )
		cin >> a[i];
	for (int i = 1; i <= n; i ++ )
		for (int j = 0; j <= i - 2; j ++ )
			for (int k = 0; k <= j; k ++ )
				dp[i][j] = max(dp[i][j], dp[i - k - 1][j - k] + (a[i - k - 1] - a[i]) * (a[i - k - 1] - a[i]));
	for (int k = 1; k <= n; k ++ )
		cout << dp[n][min(2 * k, n - 2)] << "\n";
	return 0;
}

E.An Interesting Sequence

题意:

构造一个长为 \(n\) 的序列 \(a\)\(a_1 = k(k > 1)\),且 \(a_i > 1\)\(gcd(a[i - 1], a[i]) = 1(1 < i <= n)\),问 \(\sum_{i = 1}{n} a_i\) 最小。

思路:

最小的两个大于 1 的互质的数就是 2 和 3。因为第一位是 \(k\),第二位先找到一个与 \(k\) 互质的数,设为 \(p\),如果它和 2 互质,后面就填 2 3 2 3...,否则填 3 2 3 2...。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n, k;
	cin >> n >> k;
	auto isprime = [&](int x){
		for (int i = 2; i * i <= x; i ++ )
			if (x % i == 0)
				return false;
		return true;
	};
	int p = 0;
	for (int i = 2; ; i ++ ){
		if (gcd(i, k) == 1 && isprime(i)){
			p = i;
			break;
		}
	}
	LL ans = k + p;
	int x;
	if (gcd(p, 2) == 1) x = 2;
	else x = 3;
	for (int i = 3; i <= n; i ++ ){
		ans += x;
		x = 5 - x;
	}
	cout << ans << "\n";
	return 0;
}

F.Infinity Tree

题意:

刚开始树有一个节点,每秒钟每个节点(按照编号从小到大依次来)会多出 \(k\) 个子节点,编号由小到大依次增加,\(t\) 次询问,每次告诉 \(k\),求 \(x\)\(y\)\(lca\)

思路:

开 int128 暴力求 \(lca\) 即可。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
LL k, x, y;
__int128 get(LL x){
	__int128 ans = 1;
	while(ans * (k + 1) < x)
		ans *= (k + 1);
	return ans;
}
void solve(){
	cin >> k >> x >> y;
	__int128 p = get(x), q = get(y);
	while(x != y){
		if (x > y){
			x = (x - p + k - 1) / k;
			p = get(x);
		}
		else{
			y = (y - q + k - 1) / k;
			q = get(y);
		}
	}
	cout << x << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

J.A Game about Increasing Sequences

题意:

有一个数组,\(Alice\)\(Bob\) 轮流取数,每次取开头或者结尾的数,要求除了第一个数外其他取的数要严格大于前一个人取的数,不能操作的人输,\(Alice\) 先手,如果先手胜输出 "Alice",否则输出 "Bob"。

思路:

不论后手怎么操作,先手跟就是了,所以只有当前面和后面的递增序列的长度都为偶数的时候,才输出 "Bob",否则 \(Alice\) 选择一条奇数的路径就能赢。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n;
	cin >> n;
	vector <int> a(n);
	for (int i = 0; i < n; i ++ )
		cin >> a[i];
	int L = 1, R = 1;
	for (int i = 1; i < n; i ++ , L ++ )
		if (a[i - 1] >= a[i])
			break;
	for (int i = n - 2; i >= 0; i -- , R ++ )
		if (a[i] <= a[i + 1])
			break;
	if (L % 2 == 0 && R % 2 == 0) cout << "Bob\n";
	else cout << "Alice\n";
	return 0;
}

L.Quadruple

题意:

给定一个只包含 'I','C','P' 的字符串,进行 \(q\) 次询问,输出每次询问的区间中包含 "ICPC" 子序列的数量之和。

思路:

通过前缀和统计各种组合的答案,通过做差求答案即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353, N = 2e6 + 10;
using LL = long long;
struct data{
	LL I, C, P;
	LL IC, CP, PC;
	LL ICP, CPC;
	LL ICPC;
	void Mod(){
		I %= mod, C %= mod, P %= mod;
		IC %= mod, CP %= mod, PC %= mod;
		ICP %= mod, CPC %= mod;
		ICPC %= mod;
	}
}d[N];
pair <int, int> q[N];
LL countPC(int L, int R){
	return (d[R].PC - d[L - 1].PC
		- d[L - 1].P * (d[R].C - d[L - 1].C)) % mod;
}
LL countCPC(int L, int R){
	return (d[R].CPC - d[L - 1].CPC
		- d[L - 1].C * countPC(L, R) % mod
		- d[L - 1].CP * (d[R].C - d[L - 1].C) % mod) % mod;
}
LL countICPC(int L, int R){
	return (d[R].ICPC - d[L - 1].ICPC
		- d[L - 1].I * countCPC(L, R) % mod
		- d[L - 1].IC * countPC(L, R) % mod
		- d[L - 1].ICP * (d[R].C - d[L - 1].C) % mod) % mod;
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n, Q;
	cin >> n >> Q;
	string s;
	cin >> s;
	s = '-' + s;
	for (int i = 1; i <= n; i ++ ){
		d[i] = d[i - 1];
		if (s[i] == 'I'){
			d[i].I ++ ;
		}
		else if (s[i] == 'C'){
			d[i].C ++ ;
			d[i].IC += d[i - 1].I;
			d[i].PC += d[i - 1].P;
			d[i].CPC += d[i - 1].CP;
			d[i].ICPC += d[i - 1].ICP;
		}
		else if (s[i] == 'P'){
			d[i].P ++ ;
			d[i].CP += d[i - 1].C;
			d[i].ICP += d[i - 1].IC;
		}
		d[i].Mod();
	}
	LL x, a, b, p;
	cin >> x >> a >> b >> p;
	for (int i = 0; i < Q; i ++ ){
		x = (a * x + b) % p;
		q[i].first = x % n + 1;
	}
	for (int i = 0; i < Q; i ++ ){
		x = (a * x + b) % p;
		q[i].second = x % n + 1;
	}
	LL ans = 0;
	for (int i = 0; i < Q; i ++ ){
		auto [L, R] = q[i];
		if (L > R) swap(L, R);
		ans = (ans + countICPC(L, R)) % mod;
	}
	cout << (ans + mod) % mod << "\n";
	return 0;
}
posted on 2022-10-13 10:22  Hamine  阅读(59)  评论(0编辑  收藏  举报