Codeforces Round #684 (Div. 2)题解

A. Buy the String

题解:

循环一遍判断是否转换哪个更便宜即可

代码:

/*
 * @Author : Nightmare
 */
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 100005
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
void solve(){
    int n, c0, c1, h; cin >> n >> c0 >> c1 >> h;
    string ss; cin >> ss;
    int ans = 0;
    for(auto &ch : ss){
        if(ch == '0'){
            ans += min(c0, c1 + h);
        }else{
            ans += min(c1, c0 + h);
        }
    }
    cout << ans << '\n';
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("D:\\in.txt", "r", stdin);
#endif
    int T; cin >> T; while(T--) solve();
#ifndef ONLINE_JUDGE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}
B. Sum of Medians

题解:

通过n求出中间的位置为(n + 1) / 2,贪心将每组的前(n + 1) / 2 - 1个数放在前面,后面对每一组补成n个即可。

代码:

/*
 * @Author : Nightmare
 */
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 200005
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
int a[N];
void solve(){
    int n, k; scanf("%lld %lld", &n, &k);
    for(int i = 1 ; i <= n * k ; i ++) scanf("%lld", &a[i]);
    int ans = 0, pq = (n + 1) / 2 - 1;
    if(n == 1){
        for(int i = 1 ; i <= n * k ; i ++) ans += a[i];
        cout << ans << '\n';
        return ;
    }
    if(n == 2){
        for(int i = 1 ; i <= n * k ; i += 2) ans += a[i];
        cout << ans << '\n';
        return ;
    }
    for(int i = k * pq + 1 ; i <= n * k ; i += n - pq) ans += a[i];
    cout << ans << '\n';
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("D:\\in.txt", "r", stdin);
#endif
    int T; cin >> T; while(T--) solve();
#ifndef ONLINE_JUDGE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}
C2. Binary Table (Hard Version)

题解:

模拟

对于一个2 x 2 的区域,按照区域中间的1的个数进行划分。

如果区域中没有1,不处理。

如果有一个1,对任意一个0进行一次操作,可以形成两个1的形式。

如果有两个1,对其中一个1进行一次操作,可以形成三个1的形式。

如果有三个1,对0处理一次即可。

如果有四个1,对任意一个1处理后,变成只有一个1的形式。

容易发现,每种划分都可以通过0~4次处理后变为有三个1的形式,所以操作次数 <= 2 * 2,总操作次数 <= n * m

当边界为奇数时,先将边界的1~2个1转化为0后,在统一进行处理。

代码:

/*
 * @Author : Nightmare
 */
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 105
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
char str[N][N]; int a[N][N];
vector<PII> v;
struct node{ int a, b; };
vector<node> res;
void change(int x, int y){
    for(int i = 0 ; i < 4 ; i ++){
        if(v[i].first == x && v[i].second == y) continue;
        res.push_back({v[i].first, v[i].second});
        a[v[i].first][v[i].second] ^= 1;
    }
}
void solve(){
    int n, m; scanf("%d %d", &n, &m);
    res.clear();
    for(int i = 1 ; i <= n ; i ++) scanf("%s", str[i] + 1);
    for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= m ; j ++) a[i][j] = (str[i][j] - '0');
    if((n & 1) && (m & 1) && a[n][m] == 1){ // 如果右下角为1,区域中任取一个非右下角的点操作即可。
        v.clear();
        v.emplace_back(n - 1, m - 1);
        v.emplace_back(n - 1, m);
        v.emplace_back(n, m - 1);
        v.emplace_back(n, m);
        change(n - 1, m - 1);
    }
    if(n & 1){ // 处理下边界
        for(int i = 2 ; i <= m ; i += 2){
            v.clear();
            v.emplace_back(n, i - 1);
            v.emplace_back(n, i);
            v.emplace_back(n - 1, i - 1);
            v.emplace_back(n - 1, i);
            if(a[n][i - 1] + a[n][i] == 2){ // 两个值都为1,对两个格子都进行操作一次
                change(n, i - 1);
                change(n, i);
            }else if(a[n][i - 1] + a[n][i] == 1){ // 对为0的格子操作一次
                if(a[n][i - 1] == 0) change(n, i - 1);
                else change(n, i);
            }
        }
    }
    if(m & 1){ // 处理右边界
        for(int i = 2 ; i <= n ; i += 2){
            v.clear();
            v.emplace_back(i, m);
            v.emplace_back(i - 1, m);
            v.emplace_back(i, m - 1);
            v.emplace_back(i - 1, m - 1);
            if(a[i][m] + a[i - 1][m] == 2){ // 两个值都为1,对两个格子都进行操作一次
                change(i, m);
                change(i - 1, m);
            }else if(a[i][m] + a[i - 1][m] == 1){ // 对为0的格子操作一次
                if(a[i][m] == 0) change(i, m);
                else change(i - 1, m);
            }
        }
    }
    for(int i = 2 ; i <= n ; i += 2){
        for(int j = 2 ; j <= m ; j += 2){
            v.clear();
            v.emplace_back(i - 1, j - 1);
            v.emplace_back(i - 1, j);
            v.emplace_back(i, j - 1);
            v.emplace_back(i, j);
            if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 1){
                for(int k = 0 ; k < 4 ; k ++){
                    if(a[v[k].first][v[k].second] == 1){
                        for(int p = 0 ; p < 4 ; p ++) // 对其他所有为0的格子都操作一次即可
                            if(p != k)
                                change(v[p].first, v[p].second);
                        break;
                    }
                }
            }else if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 2){
                for(int p = 0, flag = 0; p < 4 && !flag ; p ++){
                    for(int q = p + 1 ; q < 4 ; q ++){
                        if(a[v[p].first][v[p].second] == 1 && a[v[q].first][v[q].second] == 1){
                            change(v[p].first, v[p].second); // 对两个为1的格子都操作一次
                            change(v[q].first, v[q].second);
                            flag = 1;
                            break;
                        }
                    }
                }
            }else if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 3){
                for(int k = 0 ; k < 4 ; k ++){
                    if(a[v[k].first][v[k].second] == 0){
                        change(v[k].first, v[k].second); // 直接操作为0的格子即可
                        break;
                    }
                }
            }else if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 4){
                change(i - 1, j - 1); // 对任意一个格子操作一次变为只有1个1的形式
                change(i - 1, j);
                change(i, j - 1);
                change(i, j);
            }
        }
    }
    cout << res.size() / 3 << '\n';
    for(int i = 0 ; i < res.size() ; i += 3){
        cout << res[i].a << ' ' << res[i].b << ' ';
        cout << res[i + 1].a << ' ' << res[i + 1].b << ' ';
        cout << res[i + 2].a << ' ' << res[i + 2].b << '\n';
    }
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("D:\\in.txt", "r", stdin);
#endif
    int T; cin >> T; while(T--) solve();
#ifndef ONLINE_JUDGE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}
E. Greedy Shopping

题解:

操作1:1~x区间中所有小于y的数置为y

操作2:从x开始向右走,期间遇到的东西能买就买,问走到n总共能买多少件?

区间置max,考虑吉司机线段树,通过只修改区间min < val的区间进行剪枝,对于第二个操作,每次二分找到小于val的位置,再向右二分最多能连续买的位置,根据势能分析,每买一段区间,val的值一定下降至少一半,因此选取次数 < l o g ( v a l ) log(val) log(val)次,复杂度 O ( n l o g n 2 ) O(nlogn^2) O(nlogn2)

代码:

/*
 * @Author : Nightmare
 */
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 200005
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
int n, Q, a[N];
struct SegmentBeat{
    static const int maxn = 2e5 + 5;
    struct node{ int l, r, mi, sum, tag; }t[maxn * 4];
    void pushup(int rt){
        t[rt].sum = t[ls].sum + t[rs].sum;
        t[rt].mi = min(t[ls].mi, t[rs].mi);
    }
    void update(int rt, int v){
        t[rt].mi = v;
        t[rt].tag = max(t[rt].tag, v);
        t[rt].sum = (t[rt].r - t[rt].l + 1) * v;
    }
    void pushdown(int rt){
        if(t[rt].tag){
            update(ls, t[rt].tag); update(rs, t[rt].tag);
            t[rt].tag = 0;
        }
    }
    void build(int rt, int l, int r){
        t[rt].l = l; t[rt].r = r;
        if(l == r){ t[rt].sum = t[rt].mi = a[l]; return ; }
        int mid = (t[rt].l + t[rt].r) >> 1;
        build(ls, l, mid); build(rs, mid + 1, r);
        pushup(rt);
    }
    void change(int rt, int l, int r, int v){
        if(l <= t[rt].l && t[rt].r <= r){
            if(v > t[rt].mi) update(rt, v);
            return ;
        }
        pushdown(rt);
        int mid = (t[rt].l + t[rt].r) >> 1;
        if(l <= mid) change(ls, l, r, v);
        if(r > mid) change(rs, l, r, v);
        pushup(rt);
    }
    void set_max(int rt, int x, int y){
        if(t[rt].l == t[rt].r){
            if(t[rt].l <= x) change(1, t[rt].l, x, y);
            return ;
        }
        pushdown(rt);
        if(t[ls].mi <= y) set_max(ls, x, y);
        else set_max(rs, x, y);
    }
    int query_sum(int rt, int l, int r){
        if(l > r) return 0;
        if(l <= t[rt].l && t[rt].r <= r) return t[rt].sum;
        pushdown(rt);
        int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
        if(l <= mid) ans += query_sum(ls, l, r);
        if(r > mid) ans += query_sum(rs, l, r);
        return ans;
    }
    int find(int rt, int val){
        if(t[rt].l == t[rt].r){
            if(t[rt].sum <= val) return t[rt].l;
            else return t[rt].l - 1;
        }
        pushdown(rt);
        int mid = (t[rt].l + t[rt].r) >> 1;
        if(t[ls].sum <= val) return find(rs, val - t[ls].sum);
        else return find(ls, val);
    }
    int lower_bound(int rt, int val){
        if(t[rt].l == t[rt].r){
            if(t[rt].sum <= val) return t[rt].l;
            else return t[rt].l + 1;
        }
        if(t[ls].mi <= val) return lower_bound(ls, val);
        else return lower_bound(rs, val);
    }
    int query_min(int rt, int k){
        if(t[rt].l == t[rt].r) return t[rt].sum;
        pushdown(rt);
        int mid = (t[rt].l + t[rt].r) >> 1;
        if(k <= mid) return query_min(ls, k);
        else return query_min(rs, k);
    }
}seg;

void solve(){
    cin >> n >> Q;
    for(int i = 1 ; i <= n ; i ++) cin >> a[i];
    seg.build(1, 1, n);
    while(Q --){
        int opt, x, y; cin >> opt >> x >> y;
        if(opt == 1){
            if(seg.query_sum(1, x, x) < y)
                seg.set_max(1, x, y);
        }else if(opt == 2){
            int ans = 0;
            x = max(x, seg.lower_bound(1, y));
            while(x <= n){
                int r = seg.find(1, seg.query_sum(1, 1, x - 1) + y);
                y -= seg.query_sum(1, x, r);
                ans += r - x + 1;
                x = max(r + 2, seg.lower_bound(1, y));
            }
            cout << ans << '\n';
        }
    }
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("D:\\in.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    solve();
#ifndef ONLINE_JUDGE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值