首页 > 其他分享 >Educational Codeforces Round 170 (Rated for Div. 2)

Educational Codeforces Round 170 (Rated for Div. 2)

时间:2024-10-16 15:20:59浏览次数:1  
标签:Educational Rated return int i32 sum Codeforces using mint

A. Two Screens

难点是读题,找到最长公共前缀即可。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;

void solve(){
    string s, t;
    cin >> s >> t;

    int res = s.size() + t.size();
    int i = 0;
    while(i < s.size() and i < t.size() and s[i] == t[i])
        i ++, res --;
    if(i > 0) res ++;
    cout << res << "\n";
}


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int T;
    cin >> T;
    while(T --) solve();
    return 0;
}

B. Binomial Coefficients, Kind Of

打表找规律

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    
    int N = 1e5;
    vi f(N + 1);
    f[0] = 1;
    for(int i = 1; i <= N; i ++)
        f[i] = f[i - 1] * 2 % mod;
    int T;
    cin >> T;
    vi n(T), k(T);
    for(auto &i : n) cin >> i;
    for(auto &i : k) cin >> i;

    for(int i = 0 ; i < T; i ++) {
        if(n[i] == k[i]) cout << "1\n";
        else cout << f[k[i]] << "\n";
    }
    return 0;
}

C. New Game

首先我们可以统计出每个数字出现的次数。

可以用双指针求出最大的\([l,r]\),满足区间内的数至少出现一次且\(r < l + k\)。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;

void solve(){
    int n, k;
    cin >> n >> k;

    map<int, int> cnt;
    for(int i = 0, x; i < n ; i ++) 
        cin >> x, cnt[x] ++;

    vector<pii> a;
    for(auto it : cnt) a.push_back(it);

    int m = a.size();
    int res = 0, sum = 0;
    for(int l = 0, r = -1; r < m;) {
        if(r < l) {
            if(l >= m) break;
            assert(sum == 0);
            sum = a[l].second , r = l;
        } 
        while(r + 1 < m and a[r + 1].first < a[l].first + k and a[r + 1].first == a[r].first + 1)
            r ++, sum += a[r].second;
        res = max(res, sum);
        sum -= a[l].second, l ++;
    }
    cout << res << "\n";
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    
    int T;
    cin >> T;
    while(T --) solve();
    return 0;
}
 

D. Attribute Checks

考虑前缀中\(i\)中有\(sum\)点属性点,我们用\(f[x]\)表示当前分配\(x\)点智力,\(y = sum - x\)点力量可以满足多少次检查。

现在有三种情况。

如果当前是智力检测\(r_i\),则分配了\(x\in[r_i, sum]\)的\(f[x]\)均加\(1\)。

如果当前是力量检测\(r_i\),则分配了\(y\in[-r_i, sum]\)的\(f[x]\)均加\(1\)。

这两种情况是区间修改。

如果当前是一个待分配的智力点,则\(f[x]\)可以从\(f[x],f[x-1]\)转移过来。

这种情况是单点查询。

因此我们可以用一个树状数组来维护。

但是,我们注意到\(dp\)操作,因此我们可以直接新建一个树状数组更新好之后再赋值回去。

\(f[x]\)的值域是\(m\),至多重建\(m\)次,因此重建的总复杂度是\(O(m^2\log m)\)。

区间修改的次数是\(n\),复杂度是\(O(n\log m)\)。

因此最终的复杂度就是\(O(n \log m)\)。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;

struct BinaryIndexedTree{
#define lowbit(x) ( x & -x )
    int n;
    vector<int> b;

    BinaryIndexedTree(int n) : n(n) , b(n + 1 , 0){};
    
    void modify(int i , int y) {
        for(; i <= n ; i += lowbit(i) ) b[i] += y;
        return;
    }

    void modify(int l, int r, int y) {
        l ++ , r ++;
        modify(l, y), modify(r + 1, -y);
    }

    int calc(int i){
        i ++;
        int sum = 0;
        for( ; i ; i -= lowbit(i) ) sum += b[i];
        return sum;
    }
};

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    
    int n, m;
    cin >> n >> m;

    
    int sum = 0;

    BinaryIndexedTree f(m + 1);
    
    for(int i = 0 , x ; i < n; i ++) {
        cin >> x;
        if(x == 0) {
            sum ++;
            BinaryIndexedTree g(m + 1);
            g.modify(0 , 0, f.calc(0));
            for(int j = 1, x; j <= sum; j ++) {
                x = max(f.calc(j), f.calc(j - 1));
                g.modify(j, j, x);
            }
            f = move(g);
        } else if(x > 0) {
            if(x > sum) continue;
            f.modify(x, sum , 1);
        } else {
            x = - x;
            if(x > sum) continue;
            f.modify(0, sum - x, 1);
        }
    }

    int res = 0;
    for(int i = 0; i <= m; i ++)
        res = max(res, f.calc(i));
    cout << res;
    return 0;

}
 

其实可以注意到区间只有当获得能力值是才会查询,并且每次查询是要查询全部值。因此我们可以直接用差分来实现区间修改,对于查询我们可以直接求出前缀和,然后再进行转移。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    vi f(m + 2);
    for (int x, sum = 0; n; n--) {
        cin >> x;
        if (x == 0) {
            sum ++;
            for (int i = 1; i <= m; i++)
                f[i] += f[i - 1];
            for (int i = m; i > 0; i--)
                f[i] = max(f[i], f[i - 1]);
            for (int i = m; i > 0; i--)
                f[i] = f[i] - f[i - 1];
        } else if (x > 0) {
            if (x > sum) continue;
            f[x]++, f[sum + 1]--;
        } else {
            x = -x;
            if (x > sum) continue;
            f[0]++, f[sum - x + 1]--;
        }
    }

    for (int i = 1; i <= m; i++)
        f[i] += f[i - 1];
    cout << ranges::max(f);

    return 0;
}

E. Card Game

对于花色为\(1\)的牌,Alice 拿到的牌数一定不少于 Bob。对于花色不为\(1\)的牌,Alice 拿到的牌数一定不多于Bob。

我们在分配的时候可以一次分配两张牌,其中较大的给 Alice,另一张给 Bob。

设 dp 状态\(f[i][j]\)为某种花色的牌,对于前\(i\)张牌,分配了\(i-j\)张牌,剩下\(j\)张牌的方案数,因此一定有\((i-j) | 2\),也就是\(i,j\)奇偶性相同。

对于第\(i\)牌有两种情况。如果不分配,则前\(i-1\)张牌分配了\(j-1\)张。如果分配,则需要一张之前没有分配的牌,因此前\(i-1\)张分配了\(j+1\)张。因此有如下转移

\[f[i][j] = f[i-1][j - 1] + f[i - 1][j + 1] \]

考虑只有第一种花色Alice可以多拿。其他花色只能 Bob 多拿,并且 Bob 每多拿一张,Alice 就要消耗一张花色 1 的牌。因此我们可以记 dp 状态为\(g[i][j]\),表示前\(i\)种花色的牌,此时 Alice还多出来了几张花色为 1 的牌。对于花色 1 的牌,因为只能是 Alice 多拿,因此\(g[1][i] = f[m][i]\)。对于其他花色的牌,我们可以枚举出 Bob 多拿了\(k\)张,则存在转移

\[g[i][j] += g[i-1][j + k] * f[m][j] \]

注意这里的\(j,k\)都只能是偶数。

对于第二个 dp 可以\(O(N^3)\)转移即可。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;

#define int i64


using vi = vector<int>;
using pii = pair<int,int>;

const int mod = 998244353;


struct mint {
    int x;

    mint(int x = 0) : x(x) {}

    int val() {
    	return x = (x % mod + mod) % mod;
    }

    mint &operator=(int o) { return x = o, *this; }

    mint &operator+=(mint o) { return (x += o.x) >= mod && (x -= mod), *this; }

    mint &operator-=(mint o) { return (x -= o.x) < 0 && (x += mod), *this; }

    mint &operator*=(mint o) { return x = (i64) x * o.x % mod, *this; }

    mint &operator^=(int b) {
        mint w = *this;
        mint ret(1);
        for (; b; b >>= 1, w *= w) if (b & 1) ret *= w;
        return x = ret.x, *this;
    }

    mint &operator/=(mint o) { return *this *= (o ^= (mod - 2)); }

    friend mint operator+(mint a, mint b) { return a += b; }

    friend mint operator-(mint a, mint b) { return a -= b; }

    friend mint operator*(mint a, mint b) { return a *= b; }

    friend mint operator/(mint a, mint b) { return a /= b; }

    friend mint operator^(mint a, int b) { return a ^= b; }
};

i32 main() {
	int n, m;
	cin >> n >> m;

	vector f(m + 1, vector<mint>(m + 1));
	f[0][0] = 1;
	for(int i = 1; i <= m; i ++) 
		for(int j = 0; j <= i; j ++) {
			if(i % 2 != j % 2) continue;
			if(j - 1 >= 0) f[i][j] += f[i - 1][j - 1];
			if(j + 1 <= m) f[i][j] += f[i - 1][j + 1];
		}

	vector g(n + 1, vector<mint>(m + 1));

	for(int i = 0; i <= m; i += 2) 
		g[1][i] = f[m][i];

	for(int i = 2; i <= n; i ++) {
		for(int j = 0; j <= m; j += 2) {
			for(int k = 0; k + j <= m; k += 2) {
				g[i][j] += g[i - 1][k + j] * f[m][k];
			}
		}
	}

	cout << g[n][0].val();
	return 0;
}

标签:Educational,Rated,return,int,i32,sum,Codeforces,using,mint
From: https://www.cnblogs.com/PHarr/p/18470071

相关文章

  • Educational Codeforces Round 170 (Rated for Div. 2) ABCD
    来源:EducationalCodeforcesRound170(RatedforDiv.2)A.TwoScreens题意给两个屏幕,两种操作,每种操作一秒,求让两个屏幕显示两个指定字符串的最短时间操作:在一个屏幕的字符串后加任意一个字符把一个屏幕的内容复制粘贴到另一个屏幕思路先弄出相同前缀,复制一下,然后不......
  • Codeforces Round 978 (Div. 2) C. Gerrymandering 轮廓DP
    CodeforcesRound978(Div.2)C轮廓DPC.Gerrymandering思路:考虑有哪些情况呢?发现结尾只有三种情况,0.平的,1.上凸,2.下凸。那么每一种后面能出现什么呢?这样看起来就好写啦。//AConemoretimes//nndbk#include<bits/stdc++.h>usingnamespacestd;typedeflonglo......
  • 【做题记录】Codeforces Round 943 (Div. 3)/CF1968A-F
    【做题记录】CodeforcesRound943(Div.3)/CF1968A-FA暴力枚举即可。B双指针枚举即可,能匹配就匹配。C考虑构造出\(a[1]=1,a[i]=a[i-1]+x[i]\)的数列,发现满足要求。D有个明显的结论,两人最终一定是在某个点上的。于是从起点开始扫一遍,求出到每一个点的距离和路上的分数......
  • Solution - Codeforces 1628D2 Game on Sum (Hard Version)
    首先来考虑Easy。注意到的是最后输出的答案要求是模意义下的,这说明对于实数二分的做法都已经用不了了。注意到\(n,m\le3000\)的数据范围,于是一个想法就是考虑DP之类的算法。考虑到B选了\(+/-\)实际上就代表着下一轮的\(m\)是否会\(-1\),于是可以设状态为\(f_{i......
  • 「题解」Educational Codeforces Round 170 (Rated for Div. 2)
    before我不想写作业呜呜。A.TwoScreensProblemA.TwoScreensSol&Code理解题意后发现使用复制的方法完成最长公共前缀即可。#include<bits/stdc++.h>typedeflonglongll;typedefstd::pair<int,int>pii;intT;std::strings1,s2;intmain(){scanf("%d"......
  • Educational Codeforces Round 170 (Rated for Div. 2) D.Attribute Checks (没有完全
    算法显然为dp状态设计\(dp_{i,j}\)表示在第\(i\)个获得能力点的地方,之前智慧能力值为\(j\),时的最大分数状态转移显然需要从\(dp_{i-1,j}\)转移而来枚举\(j\in[0,i)\)则有(注意取\(\max\)操作要与自己相比较)设第\(i-1\)个能力点到第\(i\)个能......
  • # Educational Codeforces Round 170 (Rated for Div. 2) 题解D
    EducationalCodeforcesRound170(RatedforDiv.2)题解DD.AttributeChecks链接:Problem-D-Codeforces思路:由于\(m\)还有\(abs(r[i])\)很小,考虑dp因为每个0能对后面多少个check做出贡献是固定的,所以预处理因为我们每次的0的个数是单调不减的所以,我们上一次......
  • Educational Codeforces Round 170 (Rated for Div. 2) C. New Games
    题意转化找一些相邻的数(其中相邻定义为递增序下任意相邻两数差\(\leq1\))求相邻数中,不同数字有\(k\)种,取到数字个数的最大值算法容易想到按顺序排列观察到有点像滑动窗口,考虑用队列维护一个出现不同数字次数为\(k\)的区间,再计算代码来自转载地址voidsolv......
  • Codeforces Educational Codeforces Round 170 (Rated for Div. 2)
    A-TwoScreens大意:    给两个字符串,每次在两个空子符串进行两种操作     1、字符串末尾加一个任意字母    2、一个字符串全部复制给另一个字符串    求得到给定的两个字符串的最小操作数思路:    看最前面有多少相等即可 ......
  • Educational Codeforces Round 170 (Rated for Div. 2)
    目录写在前面A签到B结论C双指针D模拟,差分,DP,结论E计数,DP,F写在最后写在前面比赛地址:https://codeforces.com/contest/2025。妈的不想上学省赛回来昏了一天了。A签到发现最优的操作是先在一个屏幕操作得到最长公共前缀,然后复制到另一方上,再分别操作两方。特判若无公共前......