刷题之Codeforces Round #776 (Div. 3)

刷题之Codeforces Round #776 (Div. 3)

1650A. Deletions of Two Adjacent Letters

  • 题目链接:Deletions of Two Adjacent Letters

  • 思路:由于 ∣ s ∣ |s| s 为奇且每次删两个,于是可选择的字符必到某一边有偶数个。

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define per(i, a, b) for(int i = (a); i >= (b); i--)
    #define ll long long
    #define db double
    #define VI vector<int>
    #define PII pair<int, int>
    const db Pi = 3.141592653589793;
    const int INF = 0x7fffffff;
    const int N = 1e5 + 5;
    const db eps = 1e-10;
    int cas, n, m, a[N];
    string s;
    char c;
    int main(){
        cin >> cas;
        while(cas--){
            cin >> s >> c;
            int sz = s.size();
            int ok = 0;
            rep(i, 0, sz - 1){
                if(i % 2 == 1) continue;
                if(s[i] == c) ok = 1;
            }
            puts(ok ? "YES" : "NO");
        }
    }
    /*
    5
    abcde
    c
    abcde
    b
    x
    y
    aaaaaaaaaaaaaaa
    a
    contest
    t
    
    */
    

1650B. DIV + MOD

  • 题目链接:DIV + MOD

  • 题目:找到在区间 [ l , r ] [l,r] [l,r] 中的数 x x x,使得 x / a + x % a x / a+x\%a x/a+x%a 最大

  • 思路:首先肯定要找 r r r 对应的 r / a + r % a r/a+r\%a r/a+r%a,其次可查看一下商为 r / a − 1 r/a-1 r/a1,余数为 a − 1 a-1 a1 的数是否在区间内,拿来比较一下。

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define per(i, a, b) for(int i = (a); i >= (b); i--)
    #define ll long long
    #define db double
    #define VI vector<int>
    #define PII pair<int, int>
    const db Pi = 3.141592653589793;
    const int INF = 0x7fffffff;
    const int N = 1e5 + 5;
    const db eps = 1e-10;
    ll cas, n, l, r, a, ans;
    int main(){
        // freopen("1.in","r",stdin);
        ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
        cin >> cas;
        while(cas--){
            cin >> l >> r >> a;
            if(a == 1) cout << r << endl;
            else{
                ll t = r / a, rr = r % a;
                ans = 0;
                if(a * (t - 1) + a - 1 >= l) ans = t - 1 + a - 1;
                ans = max(ans, t + rr);
                cout << ans << endl;
            }
        }
    }
    /*
    */
    

1650C. Weight of the System of Nested Segments

  • 题目链接:Weight of the System of Nested Segments

  • 思路

    • 首先对所有点按照权值排序找到最小的 2 ⋅ n 2\cdot n 2n 个数,标记来选择上。
    • 按照位置排序,从左右两端向中间靠近,对应选择区间。
    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define per(i, a, b) for(int i = (a); i >= (b); i--)
    #define ll long long
    #define db double
    #define VI vector<int>
    #define PII pair<int, int>
    const db Pi = 3.141592653589793;
    const int INF = 0x7fffffff;
    const int N = 2e5 + 5;
    const db eps = 1e-10;
    int cas, n, m;
    ll sum;
    struct AC{
        int num, val, choose, pos;
    }a[N];
    bool cmp(AC a, AC b){
        return a.val < b.val;
    }
    bool cmp2(AC a, AC b){
        return a.pos < b.pos;
    }
    vector<PII> ans;
    int main(){
        cin >> cas;
        while(cas--){
            cin >> n >> m;
            rep(i, 1, m){
                scanf("%d%d", &a[i].pos, &a[i].val);
                a[i].num = i, a[i].choose = 0;
            }
            sort(a + 1, a + 1 + m, cmp);
            sum = 0;
            rep(i, 1, 2 * n){
                a[i].choose = 1;
                sum += a[i].val;
            }
            sort(a + 1, a + 1 + m, cmp2);
            ans.clear();
            int l = 1, r = m, cnt = 0;
            rep(i, 1, n){
                while(a[l].choose == 0) l++;
                while(a[r].choose == 0) r--;
                ans.push_back({a[l].num, a[r].num});
                l++, r--;
            }
            cout << sum << endl;
            for(auto i : ans) printf("%d %d\n", i.first, i.second);
        }
    }
    /*
    3
    
    3 8
    0 10
    -2 1
    4 10
    11 20
    7 -1
    9 1
    2 3
    5 -2
    
    3 6
    -1 2
    1 3
    3 -1
    2 4
    4 0
    8 2
    
    2 5
    5 -1
    3 -2
    1 0
    -2 0
    -5 -3
    */
    

1650D. Twist the Permutation

  • 题目链接:Twist the Permutation

  • 思路:由于 n ≤ 2 e 3 n\le 2e3 n2e3 数据范围较小,可以用 O ( n 2 ) O(n^2) O(n2) 复杂度。

    • 首先发现每次第 i i i 次操作要动前 i i i 个值时,后面 n − i n-i ni 个数 i + 1 , i + 2 , . . . , n i+1,i+2,...,n i+1,i+2,...,n 是不变的。于是可以从后向前看,比如先查找第 n n n 次把 n n n 从第 n n n 个位置挪到了哪里,再暴力还原。再看第 n − 1 n-1 n1 次把 n − 1 n-1 n1 从第 n − 1 n-1 n1 个位置挪到了哪里,以此类推。
    • 在还原时,可以 O ( n ) O(n) O(n) 的方法交换前半部分移动的一段和后半部分被挤到后面的一段。
    • 注意若第 i i i 次发现 i i i 还在第 i i i 个位置,则说明这次没有移动,将 d[i] = 0
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 2e3 + 5;
const db eps = 1e-10;
int cas, n, m, a[N], d[N], tmp[N];
void change(int x, int last){
    rep(i, 1, last - x) tmp[i] = a[i + x];
    rep(i, last - x + 1, last) tmp[i] = a[i - (last - x)];
    rep(i, 1, last) a[i] = tmp[i];
}
int main(){
    cin >> cas;
    while(cas--){
        cin >> n;
        rep(i, 1, n) cin >> a[i];
        per(i, n, 1){
            int pos = 0;
            rep(j, 1, n){
                if(a[j] == i){
                    d[i] = j;
                    break;
                }
            }
            if(d[i] == i) d[i] = 0;
            else change(d[i], i);
        }
        rep(i, 1, n) cout << d[i] << " ";
        cout << endl;
    }
}
/*
3
6
3 2 5 6 1 4
3
3 1 2
8
5 8 1 3 2 6 4 7

0 1 1 2 0 4 
0 0 1 
0 1 2 0 2 5 6 2 
*/

1650E. Rescheduling the Exam

  • 题目链接:Rescheduling the Exam

  • 思路:若第 i i i 场考试前的休息日子最短,则只有两种选择,即移动第 i i i 场考试或第 i − 1 i-1 i1 场考试

    • 当移动一场考试时,不妨设为第 i i i 场。将这场拿走,则其只有两个地方可以放,

      1. 最后一天:即第 d d d 天,这样增加一个间隔 d - a[last] - 1 (注意不是 d - a[n] - 1,因为有可能移动的就是 a [ n ] a[n] a[n]
      2. 剩余间隔天数中的最中间一天:这样增加间隔 (maxn - 1) / 2

      最后和当前最小间隔取最小值。

    • 于是分别删去第 i i i 场考试和第 i − 1 i-1 i1 场考试,求出剩余 n − 1 n-1 n1 场的间隔中的最大值和最小值,代入计算。

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 2e5 + 5;
const db eps = 1e-10;
int cas, n, d, a[N], MIN, posmin, ans;
VI schedule;
int calc(){
    int minn = INF, maxn = 0;
    rep(i, 1, n - 1){
        minn = min(minn, schedule[i] - schedule[i - 1] - 1);
        maxn = max(maxn, schedule[i] - schedule[i - 1] - 1);
    }
    return min(minn, max(d - schedule.back() - 1, (maxn - 1) / 2));
}
int main(){
    // freopen("1.in","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin >> cas;
    while(cas--){
        cin >> n >> d;
        a[0] = 0, MIN = INF, posmin = 0;
        rep(i, 1, n){
            cin >> a[i];
            int d = a[i] - a[i - 1] - 1;
            if(MIN > d){
                MIN = d;
                posmin = i;
            }
        }
        schedule.clear();
        //去掉posmin
        rep(i, 0, n){
            if(i != posmin) schedule.push_back(a[i]);
        }
        ans = calc();
        //去掉posmin - 1
        if(posmin > 1){
            schedule[posmin - 1] = a[posmin];
        }
        ans = max(ans, calc());
        cout << ans << endl;
    }
}
/*
9

3 12
3 5 9

2 5
1 5

2 100
1 2

5 15
3 6 9 12 15

3 1000000000
1 400000000 500000000

2 10
3 4

2 2
1 2

4 15
6 11 12 13

2 20
17 20
*/

1650G. Counting Shortcuts

  • 题目链接:Counting Shortcuts

  • 题目:无权无向图中,从 s s s 点到 t t t 点的最短路和最短路加一的路径共有多少条。

  • 思路:不妨设最短路长度为 s d i s t [ t ] sdist[t] sdist[t]

    • 易证:一条满足条件的路径一定不会重复走过同一点(这样的路径长度至少为 s d i s t [ t ] + 2 sdist[t]+2 sdist[t]+2

    • 首先可用两个 b f s bfs bfs 求出每个点到 s , t s,t s,t 点的最短距离 s d i s t [ i ] , t d i s t [ i ] sdist[i],tdist[i] sdist[i],tdist[i] 和方案数 s n u m [ i ] , t n u m [ i ] snum[i],tnum[ i] snum[i],tnum[i]

    • 其次求最短路加一的路径数量,一定是过相邻两点 i , j i,j i,j​,满足
      s d i s t [ i ] + t d i s t [ j ] + 1 = s d i s t [ t ] + 1 sdist[i]+tdist[j]+1=sdist[t]+1 sdist[i]+tdist[j]+1=sdist[t]+1
      由于一条这样的路径可能被重复计算,可以只记录 s d i s t [ i ] = s d i s t [ j ] sdist[i]=sdist[j] sdist[i]=sdist[j] 是的情况。

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 2e5 + 5;
const db eps = 1e-10;
const int mod = 1e9 + 7;
int cas, n, m, s, t, a[N];
ll sdist[N], snum[N], tdist[N], tnum[N], ans;
VI edge[N];
void bfs(int src, ll dist[], ll num[]){
    queue<int> q;
    rep(i, 1, n) dist[i] = -1, num[i] = 0;
    q.push(src), dist[src] = 0, num[src] = 1;
    while(q.size()){
        int now = q.front(); q.pop();
        for(auto nxt : edge[now]){
            if(dist[nxt] == -1){
                dist[nxt] = dist[now] + 1;
                q.push(nxt);
            }
            if(dist[nxt] == dist[now] + 1){
                (num[nxt] += num[now]) %= mod;
            }
        }
    }
}
int main(){
    // freopen("1.in","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin >> cas;
    while(cas--){
        cin >> n >> m >> s >> t;
        rep(i, 1, n) edge[i].clear();
        rep(i, 1, m){
            int u, v; cin >> u >> v;
            edge[u].push_back(v), edge[v].push_back(u);
        }
        bfs(s, sdist, snum);
        bfs(t, tdist, tnum);
        ans = 0;  //最短路
        rep(i, 1, n){
            for(auto j : edge[i]){
                if(sdist[i] + tdist[j] == sdist[t] && sdist[i] == sdist[j]){  //次最短路
                    ans += snum[i] * tnum[j] % mod;
                    ans %= mod;
                }
            }
        }
        cout << (ans + snum[t]) % mod << endl; 
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值