Codeforces Round #792 (Div. 1 + Div. 2)

Codeforces Round #792 (Div. 1 + Div. 2)

A

题意

给定一个数 \(n\) 每次 按次序 执行两个操作。

操作1:选择两个不同位置的数字并交换

操作2:删除最后一个数

重复,直到只剩下最后一个数字。问最后剩下的最小是多少。

思路

\(n\) 位数小于3时,显然是第一个数字。

\(n\) 位数大于等于3时,我们总可以在将最小数字 \(mn\) 删除前将之前移。因此总可以把 \(mn\) 换到最前

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    string s; cin >> s;
    if(s.size() == 2) {
        cout << s.back() << "\n";
    }else {
        char mn = 100;
        for(int i = 0;i < s.size();i ++) if(mn > s[i]) mn = s[i];
        cout << mn << "\n";
    }
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

B

题意

给三个正整数 \(a~,b~,c\) ,求 \(x~,y~,z\) 满足以下方程。

\[\begin{cases} x ~mod~ y = a \\ y ~mod~ z = b \\ z ~mod~ x = c \\ \end{cases} \]

思路

一开始想试着硬解这个方程,最后败给了垃圾的数学功底···

观察这个式子的形式,可以成一个环,所以只要找到 \(x~,y~,z\) 中任意一个值,其他两都可以推出,那么不妨令 \(z = c\),易得 $ y = z + b\(,\)x = y + a$

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int a,b,c; cin >> a >> b >> c;
    int z = c;
    int y = z + b;
    int x = y + a;
    cout << x << " " << y << " " << z << "\n";
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

C

题意

给一个 \(n*m\) 的网格,可以交换两列(两列不一定相同),求是否可以使得整个网格单调不减

网格单调不减指的是对任意行 \(i\) ,其中任意的 \(j < k\) ,都有 $ x_{(i,j)} - x_{(i,k)} <= 0$

思路

思维模拟

首先我们要知道,一次交换最多只能让两个元素排好序,那么,对第一个不单调的行,由于我们只可以进行一次交换,所以找到所有不在正确位置上的元素,如果个数等于2,就交换这两列,判断是否有序,如果大于2,显然就不行了(不会出现只有一个元素没在正确位置的情况)。

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int N,M; cin >> N >> M;
    vector<vector<int>> a(N + 1,vector<int>(M + 1));
    vector<bool> st(M + 1);
    for(int i = 1;i <= N;i ++) for(int j = 1;j <= M;j ++) {
        cin >> a[i][j];
    }
    int x = -1,y = -1;
    for(int i = 1;i <= N;i ++) {
        if(is_sorted(a[i].begin() + 1, a[i].end())) continue;
        vector<int> t = a[i];
        sort(t.begin() + 1, t.end());
        for(int j = 1;j <= M;j ++) if(t[j] != a[i][j]) {
            
            if(x == -1) x = j;
            else if(y == -1) y = j;
            else {
                cout << "-1\n";
                return;
            }
        }
        if(x != -1 && y != -1) break;
    }
    if(x != -1 && y != -1) {
        for(int i = 1;i <= N;i ++) swap(a[i][x], a[i][y]);
    }
    for(int i = 1;i <= N;i ++) {
        if(!is_sorted(a[i].begin() + 1,a[i].end())) {
            cout << -1 << endl;
            return;
        }
    }
    if(x == -1 && y == -1) x = y = 1;
    cout << x << " " << y << endl;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

D

题意

\(n\) 个陷阱,第 \(i\) 陷阱伤害 \(a_i\) ,有 \(k\) 次机会跳过一个陷阱,但会使得之后所有的陷阱多产生 \(1\) 的额外伤害

最小化受到的伤害

思路

贪心

dp时间复杂度太大,开始考虑贪心。

单看跳过第 $i $ 个陷阱,对答案的贡献是 $a_i - (n - i) $ ,猜测贪心的选择贡献前 \(k\) 大的陷阱跳过。

证明以后补上

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int N,K; cin >> N >> K;
    vector<int> a(N + 1);
    for(int i = 1;i <= N;i ++) cin >> a[i];
    vector<PII> b(N + 1);
    
    for(int i = 1;i <= N;i ++) {
        b[i].first = a[i] - (N - i);
        b[i].second = i;
    }
    sort(b.begin() + 1,b.end());
    for(int i = N;i > N - K;i --) {
        auto [xx,id] = b[i];
        a[id] = 0;
    }
    
    int ans = 0;
    for(int i = 1, cnt = 0;i <= N;i ++) {
        if(!a[i]) cnt ++;
        else ans += a[i] + cnt;
    }
    cout << ans << endl;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

E

题意

对一个长为 \(n\) 的序列 \(a\),有 \(k\) 次机会修改任意一个数, 求 \(diff(a) - mex(a)\) 的最小值。

  • \(diff(a)\) :序列中数字的种类数
  • \(mex(a)\):序列的 \(mex\)

思路

贪心,贪 \(mex\) 最大

首先可以感觉到增加 \(mex\) 比减小 \(diff\) 更加容易。

再做一个分类讨论

假如我们现在确定了一个 \(mex\) ,那么比 \(mex\) 小的数要全部存在,于是要填一些 空隙 ,如,\(mex = 4\) 时 ,\([0,1,3,5]\)\(2\) 的位置就有一个 空隙

然后,如果我们用比 \(mex\) 小的去填,会发现对答案没有任何贡献,一定只会令 \(diff + 1\) ,同时 $mex +1 $

那空隙只能用比 \(mex\) 大的去填。

确定贪心策略,我们尽可能最大化 \(mex\) ,之后再尝试减小 \(diff\)

不太好说明,具体看代码

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int N,K; cin >> N >> K;
    vector<int> a(N + 1);
    map<int,int> mp;
    for(int i = 1;i <= N;i ++) cin >> a[i], mp[a[i]] ++;
    int mex = 0;
    int rem = K;
    vector<int> v;
    for(auto [x,c] : mp) { // 求最大的 mex 当有一个空隙往里插一个值。
        while(rem && mex < x) mex ++, rem --;
        if(x == mex) mex ++;
        else v.emplace_back(c);
    }
    sort(v.begin(),v.end());
    int ans = v.size();// ------- mex xxxxxx
    for(auto c : v) { // 求最小 diff
        if(K >= c) {
            K -= c;
            ans --;
        }
    }
    cout << ans << endl;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}
posted @ 2022-05-20 20:39  Mxrurush  阅读(46)  评论(0编辑  收藏  举报