ICPC Central Russia Regional Contest, 2024

ICPC Central Russia Regional Contest, 2024

点击这里

一、A题

模拟,需要考虑两种情况,一种上升后降,一种下降后上升。

cpp 复制代码
#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.基本关系式为: a n = 2 a n − 1 + n a_{n} = 2a_{n - 1} + n an=2an−1+n

2.求其通向公式
a n = 2 n + 1 − n − 2 a_n=2^{n + 1} - n - 2 an=2n+1−n−2

3.过程:构造 a n + n + 2 = 2 ( a n − 1 + n + 1 ) a_{n} + n + 2 = 2\left( a_{n - 1} + n + 1 \right) an+n+2=2(an−1+n+1),令 c n = a n + n + 2 c_{n} = a_{n} + n + 2 cn=an+n+2,则 c n = 2 c n − 1 c_{n} = 2c_{n - 1} cn=2cn−1,首项 c 1 = a 1 + 1 + 2 = 1 + 3 = 4 c_1 = a_1 + 1 + 2 = 1 + 3 = 4 c1=a1+1+2=1+3=4。等比数列 { c n } \{ c_n \} {cn} 的通项为 c n = 4 ⋅ 2 n − 1 = 2 n + 1 c_{n} = 4 \cdot 2^{n - 1} = 2^{n + 1} cn=4⋅2n−1=2n+1,因此: a n = 2 n + 1 − n − 2 a_{n} = 2^{n + 1} - n - 2 an=2n+1−n−2

cpp 复制代码
#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二进制)

cpp 复制代码
#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的数字就是残次品的个数即在哪个瓶子里。

cpp 复制代码
#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

python 复制代码
import math
#import
n, x = map(int, input().split())
a = list(map(int, input().split()))
a.sort(reverse=True)

sum_num = 0
sum_den = 1

for i in range(n):
    pos = i + 1
    ai = 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 // g
    sum_den = new_down // g
    if sum_num >= x * sum_den:
        print("YES")
        exit()
print("NO")

六、H题

排序或运算符重载

没什么好说的,根据题目公式写就行了。

cpp 复制代码
#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)。

cpp 复制代码
#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

cpp 复制代码
#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题

纯粹的暴力,数据量太小了,像滑动窗口但不是。

cpp 复制代码
#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   k
    int 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。看的其他大佬的算法明白这样处理。长脑子了。

cpp 复制代码
#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;
}
相关推荐
Juchecar17 小时前
示例说明 Flask 调试模式的安全隐患
python
博界IT精灵18 小时前
C++入门
c++
大翻哥哥18 小时前
Python 2025:数据分析平台智能化转型与新范式
人工智能·python·数据分析
泽虞18 小时前
《C++程序设计》笔记p4
linux·开发语言·c++·笔记·算法
什么半岛铁盒18 小时前
C++项目:仿muduo库高并发服务器--------Any类的实现
linux·服务器·数据库·c++·mysql·github
玖笙&18 小时前
✨WPF编程基础【1.1】:XAML文档框架
c++·visualstudio·wpf
love530love18 小时前
EPGF 架构为什么能保持长效和稳定?
运维·开发语言·人工智能·windows·python·架构·系统架构
数据智能老司机19 小时前
用 C/C++ 从零实现 Redis——简介
c++·redis
傻啦嘿哟19 小时前
用Requests+BeautifulSoup实现天气预报数据采集:从入门到实战
开发语言·chrome·python
兆。19 小时前
python全栈-数据可视化
开发语言·python·信息可视化