Codeforces Round #821 (Div. 2)

Codeforces Round #821 (Div. 2)

Dashboard - Codeforces Round #821 (Div. 2) - Codeforces

A. Consecutive Sum

思路

  • 贪心

选择一个连续 k k k个,因此等价于找到 m o d   k = 0 , 1 , 2.. , k − 1 mod\ k=0,1,2..,k-1 mod k=0,1,2..,k1 的最大的 a a a 的和。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T;
    cin >> T;
    while (T -- ) {
        cin >> n >> k;
        for (int i = 1; i <= n; i ++) cin >> a[i];

        LL res = 0;
        for (int i = 1; i <= k; i ++) {
            int mx = 0;
            for (int j = i; j <= n; j += k)
                mx = max(mx, a[j]);
            res += mx;
        }

        cout << res << '\n';
            
    }
    return 0;
}

B. Rule of League

思路

  • 构造

由于第一轮一定有一个人输因此 x , y x,y x,y 里必须有一个 0 0 0,假设 x ! = 0 x!=0 x=0如果接下来等价于是否让每个人均赢 0 / x 0/x 0/x轮,判断 x ∣ n − 1 x|n-1 xn1是否成立即可,然后模拟就行。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T;
    cin >> T;
    while (T -- ) {
        int x, y; cin >> n >> x >> y;
        if ((x && y) || (!x && !y)) cout << -1 << '\n';
        else {
            if (x < y) swap(x, y);
            if ((n - 1) % x != 0) cout << -1 << '\n';
            else {
                int cnt = (n - 1) / x;
                int id = 2;          
                while (cnt) {
                    for (int i = 1; i <= x; i ++) cout << id << ' ';
                    id += x;
                    cnt --;
                }                                     
                cout << '\n';
            }
        }
    }
    return 0;
}

C. Parity Shuffle Sorting

思路

  • 贪心

​ 假设有 1 , 2 , 1 1,2,1 1,2,1 我们发现无论如何都可以让 2 → 1 2\to 1 21,因此先将 a 1 , a n a_1,a_n a1,an 搞成一样的,然后再将 i ∈ [ 2 , n − 1 ] i\in [2,n-1] i[2,n1]都搞成和首尾一样的即可。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T;
    cin >> T;
    while (T -- ) {
        cin >> n;
        for (int i = 1; i <= n; i ++) cin >> a[i];
        vector<PII> res;        
        if (a[1] != a[n])
            if ((a[1] + a[n]) & 1) a[n] = a[1], res.push_back({1, n});
            else a[1] = a[n], res.push_back({1, n});

        for (int i = 2; i < n; i ++) {
            if ((a[i] + a[1]) & 1) res.push_back({1, i});
            else res.push_back({i, n});
        }

        cout << res.size() << '\n';
        for (auto t : res) cout << t.x << ' ' << t.y << '\n';
    }
    return 0;
}

D2. Zero-One (Hard Version)

题意

​ 给你两个字符串 a , b a,b a,b。你可以对 a a a 串进行如下操作,选择 [ l , r ] [l,r] [l,r] a l ⊕ 1 , a r ⊕ 1 a_l\oplus 1,a_r\oplus 1 al1,ar1,如果 l + 1 = = r l+1==r l+1==r 花费 x x x,否则花费 y y y,问你将 a a a 变成 b b b 的最小花费是多少。

思路

  • d p dp dp

由于一次改变两个位置的值,因此当不同的位置为 o d d odd odd 的时候无解。

​ 首先 e a s y   v e r s i o n easy\ version easy version x ≥ y x\ge y xy n ≥ 5 n\ge 5 n5,因此我们直接贪心,设不同位置有 c n t cnt cnt个,如果 c n t = = 2 cnt==2 cnt==2 且相邻 我们有两种操作方法,直接用 x x x,或者用两个 y y y,其余情况直接用 y y y 成对消除即可。

​ 对于 D 2 D2 D2,考虑 y > x y>x y>x 的情况就不好贪心了,我们先将 a a a b b b不同的位置取出来放到 c c c数组中,考虑 d p dp dp f [ l ] [ r ] f[l][r] f[l][r]:将 l , r l,r l,r 这个区间所有不同的位置消除的最小操作数(注意这里 的 l , r l,r l,r均是 c c c中的下标),那么对于 f [ l ] [ r ] f[l][r] f[l][r] 可以从哪些子状态转移过来呢,即考虑前一个操作,这里由于 y > x y>x y>x,如果用 y y y的话区间一定越长越优,否则可能被连续的 x x x 顶替掉,而如果操作相邻的话中间和两边均一样,因为会被子状态弄到。所以只会从 f [ l + 1 ] [ r − 1 ] , f [ l + 2 ] [ r ] , f [ l ] [ r − 2 ] f[l+1][r-1],f[l+2][r],f[l][r-2] f[l+1][r1],f[l+2][r],f[l][r2] 转移过来。

​ 对于任意两个点 ( i , j ) (i,j) (i,j) 合并,会有一下情况,如果 i + 1 = j i+1=j i+1=j 可以花费 m i n ( x , 2 × y ) min(x,2\times y) min(x,2×y) ,如果 i + 1 ! = j i+1!=j i+1!=j m i n ( y , ( j − i ) × x ) min(y,(j-i)\times x) min(y,(ji)×x),因此转移的时候算一下贡献 即可。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
vector<int> ve;
LL x, y;
LL calc(int l, int r) {
    if (l + 1 == r) return min(x, y * 2);
    return min(y, x * (r - l));
}
LL f[5010][5010];
LL dfs(int l, int r) {
    if (r < l) return 0;
    if (f[l][r] != -1) return f[l][r];
    LL res = 1e18;
    res = min(res, dfs(l, r - 2) + calc(ve[r - 1], ve[r]));
    res = min(res, dfs(l + 2, r) + calc(ve[l], ve[l + 1]));
    res = min(res, dfs(l + 1, r - 1) + calc(ve[l], ve[r]));
    return f[l][r] = res;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T;
    cin >> T;
    while (T -- ) {
        cin >> n >> x >> y;
        string s, t; cin >> s >> t;
        ve.clear();        
        for (int i = 0; i <= n; i ++)
            for (int j = 0; j <= n; j ++)
                f[i][j] = -1;
        for (int i = 0; i < n; i ++)   
            if (s[i] != t[i]) ve.push_back(i + 1);
        if (ve.size() & 1) cout << -1 << '\n';
        else {
            if (ve.size() == 0) cout << 0 << '\n';
            else if (ve.size() == 2) cout << calc(ve[0], ve[1]) << '\n';
            else if (y <= x) cout << ve.size() / 2 * y << '\n';
            else cout << dfs(0, ve.size() - 1) << '\n';
            
        }
    }
    return 0;
}

E. Conveyor

题意

​ 给你 x × y x\times y x×y的的矩阵,每个格点的传送带一开始都是向右,第 0 0 0 ( 1 , 1 ) (1,1) (1,1) 有一个箱子,之后每一秒都会从 ( 0 , 0 ) (0,0) (0,0) 放置一个箱子,每一秒如果 ( i , j ) (i,j) (i,j)上有箱子话,会将箱子移动到指向的格点,然后向右的会变成指向上,向上的会指向右,给你 q q q 个询问,每次 t , x , y t,x,y t,x,y,问你第 t t t秒的时候 ( x , y ) (x,y) (x,y)上是否右箱子。

思路

  • 思维,前缀和优化

​ 想知道第 t t t秒的时候 ( x , y ) (x,y) (x,y)是否有箱子不好判断,但是我们可以求 ( i , j ) (i,j) (i,j) t t t 秒内有多少个箱子经过假设为 c n t i , j cnt_{i,j} cnti,j,假设我们求出了 c n t i , j cnt_{i,j} cnti,j了,那么他会有一半向右边走,一半向下走,由于先向右,再向下,因此 c n t i , j + 1 + = c n t i , j + 1 2 cnt_{i,j+1}+=\frac{cnt_{i,j}+1}{2} cnti,j+1+=2cnti,j+1 c n t i + 1 , j + = c n t i , j 2 cnt_{i+1,j}+=\frac{cnt_{i,j}}{2} cnti+1,j+=2cnti,j,由于从 ( 1 , 1 ) → ( x , y ) (1,1)\to(x,y) (1,1)(x,y)需要 x + y − 1 x+y-1 x+y1秒,因此只有 t − ( x + y − 1 ) t-(x+y-1) t(x+y1)个箱子可能到第 ( x , y ) (x,y) (x,y)这个点,所以我们模拟一下 t t t 秒经过了多少个,减去 t − 1 t-1 t1秒经过了多少个,减一下就知道第 t t t秒是否有箱子停在这里了。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
LL a[150][150];
int g(LL t, int x, int y) {
    memset(a, 0, sizeof a);
    a[0][0] = max(t - (x + y) + 1, 0ll);
    for (int i = 0; i <= x; i ++)
        for  (int j = 0; j <= y; j ++) {
            a[i + 1][j] += a[i][j] / 2;
            a[i][j + 1] += a[i][j] - a[i][j] / 2;
        }
    return a[x][y];
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T;
    cin >> T;
    while (T -- ) {
        LL t; cin >> t >> n >> m;
        cout << (g(t, n, m) - g(t - 1, n, m) > 0 ? "YES" : "NO") << '\n';
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值