比赛链接:
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;
}