ICPC Central Russia Regional Contest, 2024
ICPC Central Russia Regional Contest, 2024
- 一、A题
- 二、K题
- 三、C题
- 四、L题
- 五、E题
- 六、H题
- 七、N题
- 八、i题
- 九、J题
- 十、G题
点击这里
一、A题
模拟,需要考虑两种情况,一种上升后降,一种下降后上升。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int a[N],n;
bool panduanup(const int a[]) {int f = -1, end = 0 ;for (int i = 0; i < n - 1; i++) {if (a[i] < a[i + 1]) {f = i + 1;}else break;}if (f == -1) return false;for (int i = f; i < n - 1; i++) {if (a[i] > a[i + 1]) {end = i + 1;}else break;}if (end == n - 1) return true;else return false;
}
bool panduandown(const int a[]) {int f = -1, end = 0;for (int i = 0; i < n - 1; i++) {if (a[i] > a[i + 1]) {f = i + 1;}else break;}if (f == -1) return false;for (int i = f; i < n - 1; i++) {if (a[i] < a[i + 1]) {end = i + 1;}else break;}if (end == n - 1) return true;else return false;
}
int main() {ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);cin>>n;for(int i = 0; i < n; i++) {cin>>a[i];}bool up_down = panduanup(a);bool down_up = panduandown(a);if (up_down || down_up) {cout<<"YES\n";}else {cout<<"NO\n";}return 0;
}
二、K题
找规律 + 快速幂
需要用到一些高数知识。
1.基本关系式为: an=2an−1+na_{n} = 2a_{n - 1} + n an=2an−1+n
2.求其通向公式
an=2n+1−n−2a_n=2^{n + 1} - n - 2 an=2n+1−n−2
3.过程:构造 an+n+2=2(an−1+n+1)a_{n} + n + 2 = 2\left( a_{n - 1} + n + 1 \right)an+n+2=2(an−1+n+1),令 cn=an+n+2c_{n} = a_{n} + n + 2cn=an+n+2,则 cn=2cn−1c_{n} = 2c_{n - 1}cn=2cn−1,首项 c1=a1+1+2=1+3=4c_1 = a_1 + 1 + 2 = 1 + 3 = 4c1=a1+1+2=1+3=4。等比数列 {cn}\{ c_n \}{cn} 的通项为 cn=4⋅2n−1=2n+1c_{n} = 4 \cdot 2^{n - 1} = 2^{n + 1}cn=4⋅2n−1=2n+1,因此:an=2n+1−n−2a_{n} = 2^{n + 1} - n - 2an=2n+1−n−2
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1e9+9;
int n;long long qmi(long long a,long long b) {long long res = 1;while(b) {if (b&1) {res = res * a % mod;}a = a * a % mod;b = b >> 1;}return res % mod;
}signed main() {ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);cin >> n;int ans = ((qmi(2,n + 1) - n % mod - 2) % mod + mod) % mod;cout << ans << '\n';return 0;
}
三、C题
组合计数 + 模拟加法
需要用到__128类型(long long会卡)
乘以2的x次方对多少个1没有影响,可以看作左移x位(注意题目中Binary二进制)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;int main() {long long n, m, k;cin >> n >> m >> k;if (n == m) {cout << 1 << endl;return 0;}long long d = abs(n - m);if (d >= 100) {vector<__int128> comb(k+1);comb[0] = 1;for (int i = 1; i <= k; i++) {comb[i] = comb[i-1] * (k - i + 1) / i;}int ans = 0;for (int i = 0; i <= k; i++) {__int128 num = comb[i];int cnt = 0;while (num > 0) {if (num & 1) cnt++;num >>= 1;}ans += cnt;}cout << ans << endl;} else {int L = d * k + 1000;vector<int> bits(L, 0);bits[0] = 1;for (int i = 0; i < k; i++) {vector<int> new_bits(L, 0);int carry = 0;for (int j = 0; j < L; j++) {int s = carry;s += bits[j];if (j >= d) {s += bits[j - d];}new_bits[j] = s % 2;carry = s / 2;}bits = new_bits;}int ans = 0;for (int i = 0; i < L; i++) {if (bits[i] == 1) {ans++;}}cout << ans << endl;}return 0;
}
四、L题
思维 + 交互设计
在瓶子中分别取1 2 3 …个最后总和减去药片数量 * 500的数字就是残次品的个数即在哪个瓶子里。
#include <bits/stdc++.h>
using namespace std;
int N;
int main() {scanf("%d",&N);printf("%d\n",N);long long pillnum = 0;for(int i = 1; i <= N; i++) {printf("%d %d\n",i,i);pillnum += i;}fflush(stdout);long long sum = 0;scanf("%lld",&sum);printf("! %lld\n",sum - pillnum * 500);fflush(stdout);return 0;
}
五、E题
注意这道题本来以为要用高精度所以想着python处理起来简单,用python写的,结果没用上。
本题目有小坑:不能直接模拟题目中的除法后加和,必须通分后化简最后加和。因为精度问题。作者给你们试过了wa
import math
#import
n, x = map(int, input().split())
a = list(map(int, input().split()))
a.sort(reverse=True)sum_num = 0
sum_den = 1for i in range(n):pos = i + 1ai = a[i]up = ai down = pos new_up = sum_num * down + up * sum_den #小坑new_down = sum_den * down # 化简分数g = math.gcd(new_up, new_down)sum_num = new_up // gsum_den = new_down // gif sum_num >= x * sum_den:print("YES")exit()
print("NO")
六、H题
排序或运算符重载
没什么好说的,根据题目公式写就行了。
#include<bits/stdc++.h>
using namespace std;
typedef struct node {string name;int problems;int place;bool operator < (const node& n) const {return this->place < n.place;}
}node;
int doit(int rank) {int ans = 0;if (rank > 50) return 0;else if (rank >= 11) ans += 50 - rank + 1;else if (rank >= 6) ans += 40 + 2 * (10 - rank + 1);else if (rank == 5) ans += 53;else if (rank == 4) ans += 57;else if (rank == 3) ans += 62;else if (rank == 2) ans += 68;else if (rank == 1) ans += 80;return ans;
}
int cal(vector<node>& nodes) {int num = nodes.size();int ans = 0;if (num >= 1) {ans += 10 * nodes[0].problems;int rank = nodes[0].place;ans += 2 * doit(rank);}if (num >= 2) {int rank = nodes[1].place;ans += doit(rank);}if (num >= 3) {int rank = nodes[2].place;ans += doit(rank);}return ans;
}
int main() {ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);int n0;cin>>n0;vector<node> v;for(int i=0;i<n0;i++) {node temp;cin>>temp.name>>temp.problems>>temp.place;v.push_back(temp);}sort(v.begin(),v.end());int n1;cin>>n1;vector<node> v1;for(int i=0;i<n1;i++) {node temp;cin>>temp.name>>temp.problems>>temp.place;v1.push_back(temp);}sort(v1.begin(),v1.end());int n2;cin>>n2;vector<node> v2;for(int i=0;i<n2;i++) {node temp;cin>>temp.name>>temp.problems>>temp.place;v2.push_back(temp);}sort(v2.begin(),v2.end());int num1 = cal(v);int num2 = cal(v1);int num3 = cal(v2);int res = 4 * num1 + 3 * num2 + 2 * num3;cout<<res<<'\n';return 0;
}
七、N题
动态规划:dp[i]表示生成前i个字符的最小操作次数
状态转移(两种操作):
1.添加字符:从长度 i 到 i+1,操作次数 +1 dp[i+1] = min(dp[i+1], dp[i] + 1)。
2.直接跳转:若 F[i] > i(存在更长的公共前缀),则从 i 直接跳到 F[i],操作次数 +1 dp[F[i]] = min(dp[F[i]], dp[i] + 1)。
#include <bits/stdc++.h>
using namespace std;int main() {int n;cin >> n;vector<string> files(n);for (int i = 0; i < n; i++) {cin >> files[i];}string target = files[0];int L = target.size();vector<int> L_arr;for (int i = 0; i < n; i++) {int common = 0;for (int j = 0; j < files[i].size() && j < L; j++) {if (files[i][j] == target[j]) {common++;} else {break;}}L_arr.push_back(common);}sort(L_arr.begin(), L_arr.end());vector<int> F(L+1);for (int i = 0; i <= L; i++) {auto it = lower_bound(L_arr.begin(), L_arr.end(), i);if (it != L_arr.end()) {F[i] = *it;} else {F[i] = L;}}vector<int> dp(L+1, 1e9);dp[0] = 0;for (int i = 0; i <= L; i++) {if (i < L) {dp[i+1] = min(dp[i+1], dp[i] + 1);}if (F[i] > i && F[i] <= L) {dp[F[i]] = min(dp[F[i]], dp[i] + 1);}}cout << dp[L] << endl;return 0;
}
八、i题
简单图论 + dfs
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int h[N],e[2 * N],ne[2 * N],idx;
inline void add(int a,int b) {e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int vis[N],du[N];
int headnum, midnum, tailnum, du3_1, du3_2, du_is_4;
inline void dfs(int t,int num,int f) {if (t == du_is_4) f = 1;if (t == du3_2 && num != 2) {if (f) {midnum = num;}else{headnum = num;}return;}for(int i = h[t]; ~i; i = ne[i]) {if (!vis[e[i]]) {vis[e[i]] = 1;dfs(e[i],num + 1,f);vis[e[i]] = 0;}}
}
int main() {ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);memset(h,-1,sizeof h);int n;cin>>n;for (int i = 0; i < n + 2; i++) {int a,b;cin>>a>>b;add(a,b);add(b,a);}vector<int>du_is_3;for (int i = 1; i <= n; i++) {int tep = 0;for (int j = h[i]; j != -1; j = ne[j]) {tep ++;}du[i] = tep;if (tep == 3) {du_is_3.push_back(i);}if (tep == 4) {du_is_4 = i;}}du3_1 = du_is_3[0] , du3_2 = du_is_3[1];vis[du3_1] = 1;dfs(du3_1,1,0);vis[du3_1] = 0;tailnum = n + 3 - headnum - midnum;cout<<headnum<<" "<<midnum<<" "<<tailnum<<'\n';return 0;
}
九、J题
纯粹的暴力,数据量太小了,像滑动窗口但不是。
#include <bits/stdc++.h>
using namespace std;
int t[105],r[105];
int main() {ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);int n,k,c;cin>>n>>k>>c;for (int i = 0; i < c; i++) {cin>>t[i]>>r[i];// cout<<t[i]<<" "<<r[i]<<endl;}vector<vector<int>> a(105);for (int i = 0; i < c; i++) {for (int j = 1; j * t[i] <= n; j++) {a[i].push_back(j * t[i]);}}int l = 1;//1 kint i;for (i = l; i <= n - k + 1; i++) {bool f = 0;for (int j = 0; j < c; j++) {int cnt = 0;for (int p = 0; p < a[j].size(); p++) {if (a[j][p] >= i && a[j][p] <= i + k - 1) {cnt++;}}if (cnt != r[j]) {f = 1;break;}}if (!f) break;}if (i <= n - k + 1) {cout<<i<<'\n';}else {cout<<-1<<'\n';}return 0;
}
十、G题
图论 + 启发式合并 + dfs
这个题故意卡的,需要用到启发式合并。思路很简单,作者之前真的没写过要启发式合并的题。这道题链式前向星建图就有些不太好用了,因为下面的dfs要以size大的节点开始到小。反而用这种建图方式好排序。
不用启发式合并会卡在test47。看的其他大佬的算法明白这样处理。长脑子了。
#include <bits/stdc++.h>
using namespace std;typedef vector<int> vi;
typedef vector<vi> IntMatrix;
typedef pair<int, int> pii;
typedef vector<pii> PairVector;
typedef vector<PairVector> PairMatrix;int n;
PairMatrix adjlist;
vi nodeColors;
vi ans;int cal_size(int node) {int size = 1;for (auto& [treesize, childnode] : adjlist[node]) {treesize = cal_size(childnode);size += treesize;}sort(adjlist[node].rbegin(), adjlist[node].rend());return size;
}unordered_map<int, int> dfs(int node) {if (adjlist[node].empty()) {ans[node] = nodeColors[node];return {{nodeColors[node], 1}};}unordered_map<int, int> colorCounts = dfs(adjlist[node][0].second);int mostcolor = ans[adjlist[node][0].second];for (int i = 1; i < adjlist[node].size(); i++) {int childNode = adjlist[node][i].second;auto childColorCounts = dfs(childNode);for (auto [color, count] : childColorCounts) {colorCounts[color] += count;if (colorCounts[color] > colorCounts[mostcolor] ||(colorCounts[color] == colorCounts[mostcolor] && color < mostcolor)) {mostcolor = color;}}}int currentColor = nodeColors[node];colorCounts[currentColor]++;if (colorCounts[currentColor] > colorCounts[mostcolor] ||(colorCounts[currentColor] == colorCounts[mostcolor] && currentColor < mostcolor)) {mostcolor = currentColor;}ans[node] = mostcolor;return colorCounts;
}int main() {ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin >> n;adjlist.assign(n + 1, {});ans.assign(n + 1, 0);nodeColors.assign(n + 1, 0);vi inDegree(n + 1, 0);for (int i = 1; i <= n; i++) {cin >> nodeColors[i];}for (int i = 0; i < n - 1; i++) {int u, v;cin >> u >> v;adjlist[u].emplace_back(0, v);inDegree[v]++;}int root = 1;for (int i = 1; i <= n; i++) {if (inDegree[i] == 0) {root = i;break;}}cal_size(root);dfs(root);for (int i = 1; i <= n; i++) {cout << ans[i] << ' ';}return 0;
}