Codeforces Round 642 (Div3)

Posted Zeoy-kkk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round 642 (Div3)相关的知识,希望对你有一定的参考价值。

K-periodic Garland

给定一个长度位\\(n\\)\\(01\\)串,每次操作可以将\\(1\\)变为\\(0\\)或者将\\(0\\)变为\\(1\\),现在你需要通过操作使得所有\\(1\\)之间的距离为\\(k\\),求最少的操作次数,注意全为\\(0\\)也算

\\(1<=n<=1e6,1<=k<=n\\)

题解:\\(dp\\) / 贪心 : 最大子段和思想

方法一:\\(dp\\) \\(O(n)\\)

状态表示:\\(f[i][0/1]\\):代表将区间\\([1,i]\\)变为合法串的最小操作次数,且第\\(i\\)位为\\(0/1\\)

状态转移:

  1. 贪心考虑只有两种情况的时候我们可以将第\\(i\\)位变成\\(1\\)
  • 若第\\(i-k\\)位也是\\(1\\),我们可以考虑将第\\(i\\)位变为\\(1\\),那么我们需要将\\([i-k+1,i-1]\\)中的所有1变为0
  • 我们同样可以考虑使第\\(i\\)位前面所有的1变为0,从第\\(i\\)位的\\(1\\)重新当作起始位置,那么我们需要将前面所有的1变为0
  • 同时如果该位本身不是\\(1\\),我们需要将其变为\\(1\\)

\\(f[i][1]=min(f[i][1]+pre[i-1]-pre[i-k],pre[i-1]) + (s[i]==\'0\')\\)

  1. 同样只有两种情况我们可以将第\\(i\\)位变为\\(0\\)
  • \\(i-1\\)位是1的情况
  • \\(i-1\\)位是0的情况
  • 如果第\\(i\\)位不是0,我们需要将其变为0

\\(f[i][0]=min(f[i-1][1],f[i-1][0])+(s[i]==\'1\')\\)

状态初始:\\(f[i]=0\\)

方法二:贪心 + 枚举对\\(k\\)余数 \\(复杂度:调和级数O(nlogn)\\)

由题意可知这些\\(1\\)一定是连续的且距离间隔\\(k\\),这说明1所处的位置对\\(k\\)取模的模数是相同的,且这些1连续,所以我们可以考虑根据对\\(k\\)的余数来枚举\\(1\\)的起始位置,所以我们不妨先将所有的1变为0

我们设\\(cnt\\):可以减免的答案贡献,或者说从起始位置到现在1的前缀和数量与0的前缀和数量之差;

  1. 对于某一位来说,我们需要其为1,并且其本身已经为1,说明我们原本不用将其变为0,所以这部分答案可以减免,\\(cnt\\)++,
  2. 对于某一位来说,我们需要其为1,但是其本身为0,说明我们这部分答案不能减免,\\(cnt\\)--,
  3. 如果\\(cnt<0\\),说明从起始位置开始0的数量已经比1的数量多了,也就是说我们将这些前面位置都变成1就比全部变为0吃亏,倒不如全部变为0,借用最大子段和的思想我们直接舍弃前面的部分,将该位置重新当成起始位置,\\(cnt=0\\)
  4. 我们在枚举过程中始终维护\\(cnt\\)的最大值即可

时间复杂度为调和级数:\\(O(nlogn)\\)

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << \'=\' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl \'\\n\'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10;

int n, k;
int f[N][2];
int pre[N];

void solve()

    cin >> n >> k;
    string s;
    cin >> s;
    s = " " + s;
    for (int i = 1; i <= n; ++i)
        pre[i] = pre[i - 1] + (s[i] == \'1\');
    for (int i = 1; i <= n; ++i)
    
        f[i][1] = min(f[max(0ll, i - k)][1] + pre[i - 1] - pre[max(0ll, i - k)], pre[i - 1]) + (s[i] == \'0\');
        f[i][0] = min(f[i - 1][1], f[i - 1][0]) + (s[i] == \'1\');
    
    cout << min(f[n][0], f[n][1]) << endl;

signed main(void)

    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    
        solve();
    
    return 0;

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << \'=\' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl \'\\n\'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10;

int n, k;

void solve()

    cin >> n >> k;
    string s;
    cin >> s;
    s = " " + s;
    int ans = 0;
    for (int i = 1; i <= n; ++i)
        if (s[i] == \'1\')
            ans++;
    int maxx = -INF;
    for (int i = 1; i <= k; ++i)
    
        int cnt = 0;
        for (int j = i; j <= n; j += k)
        
            if (s[j] == \'1\')
                cnt++;
            else
                cnt--;
            if (cnt < 0)
                cnt = 0;
            maxx = max(cnt, maxx);
        
    
    cout << ans - maxx << endl;

signed main(void)

    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    
        solve();
    
    return 0;

Decreasing Heights

给出一个 \\(n \\times m\\) 的矩阵,每个矩阵的权值代表该点的初始高度。

现在需要从点 \\(( 1 , 1 )\\) 走到点 \\(( n , m )\\) ,每一步需要满足以下条件:

  • 只能向右或向下
  • 设当前格子的高度为 \\(x\\) ,只能移动到高度为 \\(x + 1\\) 的格子上去

初始时可以进行操作,使得某个格子的高度减少一个单位。

问最少需要进行多少次操作,可以存在至少一条从点 \\(( 1 , 1 )\\) 到点 \\(( n , m )\\) 的路线

\\(1≤n,m≤100\\)

题解:\\(dp\\) + 枚举

我们发现只要确定起点\\((1,1)\\)的高度,那么对于任意位置\\((i,j)\\)的高度我们都是确定的:\\(i+j-2\\),所以我们只需要枚举起点的高度即可,但是我们怎么枚举?

我们贪心的进行枚举,每次枚举的起点高度能够保证使得位置\\((i,j)\\)上的高度不需要降低,即起码保证有一个位置我们不需要改变其高度,如果这个位置原有的高度\\(h\\),且\\(h<a[1][1]+i+j-2\\),说明我们不能通过降低起点的高度使得到达\\((i,j)\\)时不需要降低\\((i,j)\\)的高度,否则我们可以利用\\(dp\\)求出从起点到终点的最小操作次数

设起点高度为\\(h\\)

状态表示:\\(f[i][j]\\):从起点\\((1,1)\\)到达\\((i,j)\\)所需的最小操作次数

状态转移:

  1. 该位置是从上面过来的,即\\((i-1,j)->(i,j)\\)

\\(f[i][j] = min(f[i][j],f[i-1][j]+a[i][j]-(h+i+j-2)),a[i][j]>=h+i+j-2\\)

  1. 该位置是从右边过来的,即\\((i,j-1)->(i,j)\\)

\\(f[i][j] = min(f[i][j],f[i][j-1]+a[i][j]-(h+i+j-2)),a[i][j]>=h+i+j-2\\)

  1. 如果$ a[i][j]<h+i+j-2 \\(,说明位置\\)(i,j)$无法到达,我们直接跳过即可
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << \'=\' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl \'\\n\'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e2 + 10, M = 4e5 + 10;

int n, m;
int a[N][N];

int calc(int x, int y)

    vector<vector<int>> f(n + 10, vector<int>(m + 10, INF));
    int h = a[x][y] - x - y + 2;
    f[1][1] = a[1][1] + x + y - 2 - a[x][y];
    for (int i = 1; i <= n; ++i)
    
        for (int j = 1; j <= m; ++j)
        
            int cur = h + i + j - 2;
            if (cur > a[i][j])
                continue;
            f[i][j] = min(f[i][j], f[i - 1][j] + a[i][j] - cur);
            f[i][j] = min(f[i][j], f[i][j - 1] + a[i][j] - cur);
        
    
    return f[n][m];


void solve()

    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cin >> a[i][j];
    int ans = INF;
    for (int i = 1; i <= n; ++i)
    
        for (int j = 1; j <= m; ++j)
        
            if (a[1][1] + i + j - 2 < a[i][j])
                continue;
            ans = min(ans, calc(i, j));
        
    
    cout << ans << endl;

signed main(void)

    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    
        solve();
    
    return 0;

Codeforces Round #735 (Div. 2)

Codeforces Round #735 (Div. 2)

题海题目知识点
ACherry
BCobb
CMikasa
DDiane
EYou

以上是关于Codeforces Round 642 (Div3)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #642 (Div. 3)

Codeforces Round #642 (Div. 3)

Codeforces Round #642 (Div. 3)

Codeforces Round #642 (Div. 3) 题解

Codeforces Round #642 (Div. 3)A~D

Codeforces Round #642 (Div. 3)A~D