Codeforces Round #776 (Div. 3) A - F

前言:

cf稳定上分中,但是最近一场省赛的名额选拔赛却打崩了,一度让我怀疑人生,情绪低落。为什么那些队伍里甚至没有能稳定在青名的选手能打过我们?赛后补了题才发现,题都读假了,而且假得离谱。慢慢的也走出来了,队伍里也发生很多事情,该继续学习了。

有段时间没写博客了,cf 已经顺利的打到 1699 分。但感觉最近场次都没有有趣的题目,能上分纯粹是手速比较快,基本题数和学弟学妹们没差。

刷atcoder 的 abc 的效果还可以,打 cf 基本可以稳定出 abc 了,偶尔过 d。

听校内学长的建议,一直没有继续深入的学习算法,acwing提高课还没听,近期训练主要以写 cf 题 和 atcoder 为主。但感觉自己最近写 div2 的 d 还是少了点什么,该回去继续学新的算法了,也当是准备接下来的昆明了。

div3 终于可以光明正大打小号惹哈哈,这场表现分到了 2000 多分,不知道插件估计div3 准确不准确。

A - Deletions of Two Adjacent Letters

题目大意:

给一个长度为 奇数 的字符串,问两个两个删除其中的字母,是否能留下给定的字母 c.

分析:

不难发现,无论怎么删,最后留下的都是原先奇数位上的字母。因此判断一下原先奇数位上是否存在字母 c 即可

int main (){
    IOS
    int t; cin >> t;
    while (t --){
        string s; cin >> s; 
        char c; cin >> c;
        bool flag = 0;
        for (int i = 0 ; i < s.size () ; i += 2){
            if (s[i] == c){
                flag = 1;
                break;
            }
        }
        if (flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

B - DIV + MOD

题目大意:

给定一个区间 \([L,R]\) ,和 a,问对于区间中的数 \(x\), 最大的 \(x / a + x \mod a\)

分析:

假设 \(a = 3\) , 区间左端从 0 开始

那么上述公式的

  • 前一项的值变化规律为,000111222333444555666
  • 后一项的值变化规律为,012012012012012012012

把原区间划分成一段一段的,可以发现答案一定出现在最后一段的最后一位或者是倒数第二段的最后一位,我们对这两段取 max 即可,要注意判断一下存不存在倒数第二段

没想到这题卡住了我的队友

int main (){
    IOS
    int t; cin >> t;
    while (t --){
        int l, r, a; cin >> l >> r >> a;
        int t1 = r / a * a - 1;
        if (t1 >= l)
            cout << max (t1 / a + t1 % a, r / a + r % a) << endl;
        else{
            cout <<  r / a + r % a << endl;
        }
    }
    return 0;
}

C - Weight of the System of Nested Segments

题目大意:

数轴上有的 m 个点,给出每个点的下标和权值。要求你连 n 对点,要求所有点对的连线满足嵌套规则,详见题目图像。总权值等于所有点的权值和。

分析:

阅读理解题,还有赛中貌似输出没讲清楚。

找到权值最小的 n * 2 个点,然后不断输出首尾即可。要注意输出顺序是一开始给出的顺序。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;
struct node {
    int x, w, idx;
    bool operator < (const node & temp) const{
        return w < temp.w;
    }
};
bool cmp (node a, node b){
    return a.w < b.w;
}
bool cmp2 (node a, node b){
    return a.x < b.x; 
}
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        int n, m; cin >> n >> m;
        vector <node> a, b;
        ll ans = 0;
        for (int i = 1 ; i <= m ; i ++){
            int x, w; cin >> x >> w;
            a.push_back({x, w, i});
        }
        sort (a.begin(), a.end (), cmp);
        for (int i = 0 ; i < n * 2 ; i ++){
            b.push_back(a[i]);
            ans += a[i].w;
        }
        sort (b.begin(), b.end (), cmp2);
        cout << ans << endl;
        for (int i = 0, j = b.size () - 1 ; i < j ; i ++ , j --){
            cout << b[i].idx << ' ' << b[j].idx << endl;
        }
        cout << endl;
    }
    return 0;
}

D - Twist the Permutation

题目大意:

题目给了足够明确的样例解释惹。简单来说给你一个状如 123456 的数组,然后给出同样长度的随机排列,要求你按它给的要求步骤构造。

分析:

我也不知道咋想,反正发现倒着构造就能把这题做出来。

观察他给的样例,就能发现,在操作 i = x 的时候,不会影响到 x 位之后的数字,所以因而想到了倒着构造。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=2e3+7;
const double eps=1e-6;
const int mod=1e9+7;
int ans[N];
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        int n; cin >> n;
        vector <int> b (n + 1);
        for (int i = 1 ; i <= n ; i ++){
            cin >> b[i];
        }
        for (int now = n ; now >= 1 ; now --){
            int loc;
            for (int i = 1 ; i < b.size() ; i ++){
                if (b[i] == now){
                    loc = i;
                    break;
                }
            }
            ans[now] = loc % now;
            vector <int> b2;
            b2.push_back(0);
            for (int i = loc + 1 ; i < b.size() ; i ++){
                b2.push_back(b[i]);
            }
            for (int i = 1 ; i < loc ; i ++){
                b2.push_back(b[i]);
            }
            b = b2;
        }
        for (int i = 1 ; i <= n ; i ++) cout << ans[i] << ' ';
        cout << endl;
    }
    return 0;
}

E - Rescheduling the Exam

题目大意:

给一个 \(d \times 1\)的表格,里面有 n 个涂色的格子。

  • 每个涂色的格子的价值为其前面空白的格子的个数。

  • 这个表格的价值是所有涂色格子的价值的最小值。

你现在可以移动至多一个涂色的格子,到没涂色的格子上去,问怎么样移动,可以使得移动后表格的价值最大,求最大价值。

分析:

有点恶心的暴力模拟,需要一点分类讨论。

很显然,我们首先应该改变当前价值最小的格子。

如果你往这个方向走但还是不幸的 wa了,可以注意以下细节:

  1. 假如最小价值有并列,我们应当改变其中下标最小的那个。
  2. 如果确定了改变价值的格子,你既可以移动这个最小的格子,也可以移动它之前的一个格子来改变它的价值。
  3. 移动到哪里去?当前最大的中间位置,或者是整个表格的最末尾。

对于结论1,如果存在并列最小价值的不相邻格子,那么无论怎么移动,表格的最小值不会改变。如果相邻,那么显然应该移动前面的那个。

想清楚了问题,接下来就是实现了。不建议参考以下代码,比赛人都快写晕了,不过过了就是好代码

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;
typedef pair <int, int> pii;
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        int n, m; cin >> n >> m;
        vector<int> a(n + 1);
        a[0] = 0;
        for (int i = 1 ; i <= n ; i ++) cin >> a[i];

        vector <pii> b;
        for (int i = 1 ; i <= n ; i ++){
            b.push_back({a[i] - a[i - 1] - 1, i});            
        }
        sort (b.begin(), b.end ());
        vector <int> a2 = a;
        int loc = b[0].y;
        a.erase(a.begin() + loc);
        b.clear();
        for (int i = 1 ; i < n ; i ++){
            b.push_back({a[i] - a[i - 1] - 1, i});            
        }
        sort (b.begin(), b.end ());
        int smin = b[0].x;
        int ans = 0;
        ans = max ((b[n - 2].x - 1) / 2, ans);
        if (a[n - 1] != m){
            ans = max (m - a[n - 1] - 1, ans);
        }
        ans = min (ans, smin);
        if (loc > 1){
            a2.erase(a2.begin() + loc - 1);
            b.clear();
            for (int i = 1 ; i < n ; i ++){
                b.push_back({a2[i] - a2[i - 1] - 1, i});            
            }
            sort (b.begin(), b.end ());
            int smin2 = b[0].x;
            int ans2 = 0;
            ans2 = max ((b[n - 2].x - 1) / 2, ans2);
            if (a2[n - 1] != m){
                ans2 = max (m - a2[n - 1] - 1, ans2);
            }
            ans2 = min (ans2, smin2);
            ans = max (ans2, ans);
        }
        cout << ans << endl;
    }
    return 0;
}

F - Vitaly and Advanced Useless Algorithms

题目大意:

有 n 个任务,每个任务都有一个 ddl,必须给出的时限 \(a_i\) 之前完成。给出 m 个选项,每个选项有三个值e,t,p,选择一个将会花费 t 时间,为下标为 e 的任务增加 p 点进度,每个任务都将在到达或者超过 100 进度后完成。

分析:

把每个任务看成一个 100 体积的 01背包即可。求得每个任务完成的最少时间,然后记录方案即可。

会 01背包记录方案的都可以写写。

本题比起考验 dp 思维,更考验码力

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
#define endl '\n'
using namespace std;
const int N=1e5+7;
const double eps=1e-6;
const int mod=1e9+7;
int a[N], res[N];
typedef tuple <int, int, int> tii;
int main (){
    IOS
    int t; cin >> t;
    while (t --){
        int n, m; cin >> n >> m;
        vector <vector <tii>> ap(n + 1);
        vector <int> ans;
        for (int i = 1 ; i <= n ; i ++) cin >> a[i];
        for (int i = 1 ; i <= m ; i ++){
            int u, time, p; cin >> u >> time >> p;
            ap[u].push_back({time, p, i});
        }
        bool flag = 1;
        for (int i = 1 ; i <= n ; i ++){
            int nn = ap[i].size ();
            int dp[nn + 1][101];
            memset (dp, 0x3f, sizeof dp);
            dp[0][0] = 0;
            for (int j = 0 ; j < ap[i].size () ; j ++){
                int v = get <1> (ap[i][j]), w = get<0>(ap[i][j]);
                for (int k = 0 ; k <= 100 ; k ++){
                    dp[j + 1][k] = dp[j][k];
                        dp[j + 1][k] = min (dp[j + 1][k], dp[j][max (k - v, 0)] + w);
                }
            }
            if (dp[nn][100] != 0x3f3f3f3f){
                res[i] = dp[nn][100];
                int k = 100;
                for (int j = ap[i].size () - 1 ; j >= 0 ; j --){
                    int v = get <1> (ap[i][j]), w = get<0>(ap[i][j]), id = get <2>(ap[i][j]);
                    if (dp[j + 1][k] == dp[j][max (k - v, 0)] + w){
                        ans.push_back(id);
                        k -= v;
                        if (k <= 0) break;
                    }
                }
            }
            else {
                flag = 0;
                break;
            }
        }
        int sum = 0;
        for (int i = 1 ; i <= n ; i ++){
            sum += res[i];
            if (sum > a[i]){
                flag = 0;
                break;
            }
        }
        if (flag == 0) {
            cout << -1 << endl;
            continue;
        }
        cout << ans.size () << endl;
        for (auto i : ans){
            cout << i << ' ';
        }
        cout << endl;
    }
    return 0;
}

G - Counting Shortcuts

acwing 板题哦

posted @ 2022-03-16 20:05  sweet_guagua  阅读(137)  评论(0)    收藏  举报