比赛链接:

https://codeforces.com/contest/1575

A. Another Sorting Problem

题意:

\(n\) 个长为 \(m\) 的字符串,对它们进行排序,比较奇数位时要实现递增,偶数位要递减。

思路:

直接 sort 就好了。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m;
struct node{
	string s;
	int p;
}nd[N];
bool cmp(node a, node b){
	for (int i = 0; i < m; i++)
		if (a.s[i] != b.s[i])
			return (a.s[i] < b.s[i]) ^ (i & 1);
}
void solve(){
	cin >> n >> m;
	for (int i = 1; i <= n; i++){
		cin >> nd[i].s;
		nd[i].p = i;
	}
	sort (nd + 1, nd + n + 1, cmp);
	for (int i = 1; i <= n; i++)
		cout << nd[i].p << " \n"[i == n];
}
int main(){
	solve();
	return 0;
}

D. Divisible by Twenty-Five

题意:

有一个由数字、'' 和 'X' 组成的字符串,每一个''都可以被 0 到 9 的数字替代,所有的'X'都只能被 0 到 9 的一个数字替代。求所有能组成的数字能被25整除的有几个,不能含有前导零。

思路:

能被25整除的话只用看结尾的两位就可以了,最后结尾要是00,25,50,75。
1. 可以直接去对结尾两位讨论。(我写出来的有点冗长)
2. 因为字符串长度最大只有 8 位,可以去 暴力 跑所有能组成的数,然后逐一判断。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
string s;
LL expo (LL a, LL b){
	LL ret = 1;
	while (b > 0){
		if (b & 1) ret = ret * a;
		a = a * a;
		b >>= 1;
	}
	return ret;
}
int main(){
	cin >> s;
	int low = expo(10, (int)(s).size() - 1), high = expo(10, (int)(s).size()) - 1, ans = 0;  //只从可能组成数的下界遍历到上界,然后去判断
	if (low == 1) low--;
	while (low % 25) low++;
	for (; low <= high; low += 25){
		string current = to_string(low);
		char xval = '-';
		bool can = 1;
		for (int i = 0; i < (int)(s).size(); i++){
			if (s[i] == '_') continue;
			if (s[i] == 'X') {
				if (xval != '-' && xval != current[i]){
					can = 0;
					break;
				}
				xval = current[i];
			}
			else if (s[i] != current[i]){
				can = 0;
				break;
			}
		}
		ans += can;
	}
	cout << ans << "\n";
	return 0; 
}

也可以用 dp 或者 dfs 去做。

J. Jeopardy of Dropped Balls

题意:

有一个 \(n * m\) 的网格,每个格子中有个数字,1、2或3,代表当球到达这个格子的时候,球会向哪边移动,1表示向右,2表示向下,3表示向左,不论格子中是什么数字,当球离开后,数字都变成2,现在在第一行放 \(k\) 个球,分别放在 \(c_1\)\(c_2\),...,\(c_k\) (1 <= \(c_i\) <= m) 的位置,判断球最后会从哪一列离开。

思路:

因为网格的大小只有1000 * 1000,所以可以直接暴力模拟跑一遍就好了。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
const int NA = 1e5 + 10;
int n, m, k, a[N][N], c[NA];
int f(int x, int y){
	if (x > n) return y;
	if (a[x][y] == 1){
		a[x][y] = 2;
		return f(x, y + 1);
	}
	else if (a[x][y] == 2)
		return f(x + 1, y);
	else if (a[x][y] == 3){
		a[x][y] = 2;
		return f(x, y - 1);
	}
}
void solve(){
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%d", &a[i][j]);
	for (int i = 1; i <= k; i++)
		scanf("%d", &c[i]);
	for (int i = 1; i <= k; i++)
		cout << f(1, c[i]) << " \n"[i == k];
}
int main(){
	solve();
	return 0;
}

G. GCD Festival

题意:

给一个序列 \(a\),求 \(\sum_{i = 1}^n \sum_{j = 1}^n gcd(a_i, a_j) * gcd(i, j)\),结果对 1e9 + 7 取模。

思路:

推式子,参考:https://www.cnblogs.com/LacLic/p/15557637.html

代码:

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int mod = 1e9 + 7, N = 1e5 + 10;
int phi[N], a[N], cnt[N];
vector<int> fac[N];
void get_eulers(){
	for (int i = 1; i <= N - 10; i ++ ){
		for (int j = i; j <= N - 10; j += i){
			fac[j].push_back(i);
		}
	}
	phi[1] = 1;
	for (int i = 2; i <= N - 10; i ++ ){
		phi[i] = i;
		for (auto j : fac[i]){
			if (j == i) continue;
			phi[i] -= phi[j];
		}
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	get_eulers();
	int n;
	cin >> n;
	for (int i = 1; i <= n; i ++ ){
		cin >> a[i];
	}
	LL ans = 0;
	for (int i = 1; i <= n; i ++ ){
		LL s1 = 0;
		for (int j = i; j <= n; j += i){
			for (auto k : fac[a[j]]){
				cnt[k] ++ ;
			}
		}
		
		for (int j = i; j <= n; j += i){
			for (auto k : fac[a[j]]){
				if (cnt[k]){
					LL s2 = cnt[k];
					s2 = (s2 * cnt[k]) % mod * phi[k] % mod;
					
					cnt[k] = 0;
					s1 = (s1 + s2) % mod;
				}
			}
		}
		
		ans = (ans + s1 * phi[i] % mod) % mod;
	}
	cout << ans << "\n";
	return 0;
}

L. Longest Array Deconstruction

题意:

给定一个序列 \(a\),删除其中一些元素,求剩下的序列 \(b\)\(b_i = i\) 的数量最大是多少。

思路:

假设其中两个元素的下标为 \(i\)\(j(i < j)\)
删除了部分元素后,它们都对应着自己的下标,那么 \(i\) 之前移除了 \(i - a_i\) 个元素,\(j\) 之前移除了 \(j - a_j\) 个元素。
显然 \(a_i < a_j\)\(i - a_i <= j - a_j\),因为 \(j\) 前面删除的元素肯定大于等于 \(i\) 之前删除的元素。
通过这两个条件,也可以反推出 \(i < j\)
所以问题就是一个二维偏序问题。以 \(i - a_i\) 为第一维,用树状数组维护即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL n, x, ans;
struct fwt{
	LL n;
	vector <LL> a;
	fwt(LL n) : n(n), a(n + 1) {}
	LL sum(LL x){
		LL res = 0;
		for (; x; x -= x & -x)
			res = max(res, a[x]);
		return res;
	}
	void add(LL x, LL k){
		for (; x <= n; x += x & -x)
			a[x] = max(a[x], k);
	}
	LL query(LL x, LL y){
		return sum(y) - sum(x - 1);
	}
};
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> n;
	fwt a(n);
	vector < pair <LL, LL> > p;
	for (int i = 1; i <= n; i ++ ){
		cin >> x;
		p.push_back({i - x, x});
	}
	sort(p.begin(), p.end());
	for (int i = 0; i < n; i ++ ){
		if (p[i].first < 0) continue;
		LL t = a.query(1, p[i].second - 1);
		ans = max(ans, t + 1);
		a.add(p[i].second, t + 1);
	}
	cout << ans << "\n";
	return 0;
}
posted on 2022-01-29 20:07  Hamine  阅读(271)  评论(0编辑  收藏  举报