首页 > 其他分享 >Codeforces Round 860 (Div. 2)

Codeforces Round 860 (Div. 2)

时间:2023-04-09 14:11:06浏览次数:46  
标签:cout int 860 Codeforces cin leq MAXN Div define

Codeforces Round 860 (Div. 2)

Date: 04/08/2023

Link: Codeforces Round 860 (Div. 2)

A|Showstopper

Brief: 两组数 \(\{a_i\}\) 和 \(\{b_i\}\),长度都为 \(n\). \(\forall i\) , 可以交换 \(a_i\) 和 \(b_i\), 问是否可以使得 \(a_n = \max(a_i)\), \(b_n = \max(b_i)\).

Data: \(T\leq 200\), \(n\leq 100\).

Solution: 【简单思维题】

发现只需考虑当把大的放在一边,小的放在另一边时的可行性。

题解提到一个比较重要的思想:交换操作大于等于 \(2\) 时是无效的。

Complexity: \(\mathcal{O}(Tn)\).

Review: -

State: AC.

Code:

#define Justanaaaaame
#include <cstdio>
#include <iostream>
using namespace std;

#define MAXN 110

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        int a[MAXN], b[MAXN];
        for (int i = 1 ; i <= n ; ++i)
            cin >> a[i];
        for (int i = 1 ; i <= n ; ++i)
            cin >> b[i];
        for (int i = 1 ; i <= n ; ++i)
            if (a[i] < b[i])
                swap(a[i], b[i]);
        bool flag = true;
        for (int i = 1 ; i < n ; ++i)
            if (a[i] > a[n] || b[i] > b[n])
            {
                flag = false;
                break;
            }
        if (flag)
            cout << "Yes\n";
        else
            cout << "No\n";
    }
}

B|Three Sevens

Brief: \(m\) 天,每天 \(n_i\) 人参加比赛,编号分别为 \(a_{i,j}\). 每天有一个胜者,胜者在之后的比赛中不出现。构造出一个可能的胜者序列。

Data: \(T\leq 50000\), \(m\leq 50000\), \(\sum n_i\leq 50000\).

Solution: 【简单思维题】【构造】

一个比较重要的思想:倒序考虑。

倒序维护出现过的人,在每一天找一个没出现过的人即可。

Review: 实现时在循环里声明大数组TLE,放全局变量AC:声明有复杂度QAQ(滚去学 cpp 惹~

State: AC.

Code:

#define Justanaaaaame
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

#define MAXN 50010

vector <int> v[MAXN];
bool vis[MAXN];
int ans[MAXN];

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {

        int m;
        cin >> m;
        for (int i = 1 ; i <= m ; ++i)
        {
            v[i].clear();
            int n;
            cin >> n;
            for (int j = 1 ; j <= n ; ++j)
            {
                int t;
                cin >> t;
                v[i].push_back(t);
                vis[t] = false;
            }
        }
        bool flag;
        for (int i = m ; i ; --i)
        {
            flag = false;
            for (const auto &x : v[i])
                if (!vis[x])
                {
                    vis[x] = true;
                    ans[i] = x;
                    flag = true;
                }
            if (!flag)
                break;
        }
        if (flag)
        {
            for (int i = 1 ; i <= m ; ++i)
                cout << ans[i] << ' ';
            cout << "\n";
        }
        else
        {
            cout << "-1\n";
        }
    }

    return 0;
}

C|Candy Store

Brief: \(n\) 种糖,第 \(i\) 种有 \(a_i\) 颗,每颗 \(b_i\) 元。现在把第 \(i\) 种糖分成 \(a_i/d_i\) 袋,每袋 \(d_i\) 颗,那么一袋 \(c = b_i \cdot d_i\) 元。一个标签可以覆盖相邻价格一样的糖果袋,求在不改变糖的顺序的前提下,最少的标签数量。

Data: \(T\leq 100000\), \(2 \leq n\leq 200000\), \(\sum n_i\leq 20000\).

Solution: 【数学】

Observation 1: 贪心地让当前的标签覆盖更多的袋子最优;

Observation 2: \(b_i\mid c\). 对于一个标签覆盖的,\(\text{lcm}(b_i)\mid c\);

Observation 3: \(c \mid a_i\cdot b_i\) (由于 \(c \cdot (a_i/d_i) = a_i\cdot b_i\)). 对于一个标签覆盖的,\(c\mid\gcd(a_i\cdot b_i)\);

综上,只需从前往后判断新加入的是否满足 \(\text{lcm}(b_i)\mid\gcd(a_i\cdot b_i)\), 不满足则新加一个标签。

Review: 实际上离结论已经很近了,然而……

State: -> AC.

Code:

#define Justanaaaaame
#include <iostream>
using namespace std;
#define int long long

int gcd(int a, int b)
{
    while(a ^= b ^= a ^= b %= a);
    return b;
}

int lcm(int a, int b)
{
    return a * b / gcd(a, b);
}

signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        int ans = 1;
        int a1, b1;
        cin >> a1 >> b1;
        int g = a1 * b1, l = b1;
        for (int i = 2 ; i <= n ; ++i)
        {
            int a, b;
            cin >> a >> b;
            g = gcd(g, a * b);
            l = lcm(l, b);
            if (g % l)
            {
                ++ans;
                g = a * b;
                l = b;
            }
        }
        cout << ans << '\n';
    }
}

D|Shocking Arrangement

Brief: 给定整数序列,满足和为 \(0\)。需要构造一个排列,使得 \(\max\limits_{1\leq l\leq r\leq n}|a_l+a_{l+1}+\cdots+a_r|<\max(a) - \min(a)\).

Data: \(T\leq 50000\), \(1 \leq n\leq 300000\), \(\sum n_i\leq 30000\).

Solution: 【构造】【dp】

Observation 1: 左式可以写成 \(maxPrefSum - minPrefSum\);

Observation 2: 只需满足 \(maxPrefSum\leq\max(a)\) and \(minPrefSum\geq\min(a)\) 且不能同时取等。

综上,只需当前缀和 \(> 0\) 时,放一个小于 \(0\) 的数;在前缀和 \(\leq 0\) 时,放一个 \(\geq 0\) 的数。如此构造前缀和一定在最大值和最小值之间。

另外,注意到全为 \(0\) 时取等,无解。

Review: 关键在于公式的转换。注意max和min的性质。复健基本模型。

State: AC.

Code:

#define Justanaaaaame
#include <iostream>
using namespace std;

#define MAXN 300010
int np, pos[MAXN];
int nn, neg[MAXN];

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        nn = 0;
        np = 0;
        int n;
        cin >> n;
        for (int i = 1 ; i <= n ; ++i)
        {
            int t;
            cin >> t;
            if (t >= 0) pos[++np] = t;
            else        neg[++nn] = t;
        }
        if (nn == 0)
        {
            cout << "No\n";
            continue;
        }
        cout << "YES\n";
        long long prefsum = 0;
        for (int i = 1 ; i <= n ; ++i)
        {
            if (prefsum > 0)
            {
                prefsum += neg[nn];
                cout << neg[nn--] << ' ';
            }
            else
            {
                prefsum += pos[np];
                cout << pos[np--] << ' ';
            }
        }
        cout << '\n';
    }

    return 0;
}

E|Multitest Generator

Brief: 定义test: 数列的第一个数是长度-1,multitest: 数列第一个数是能将后面的数划分成test的数量。给出一列数,问对于 \(i\in[1, n-1]\) ,最少修改多少个数使得数列 \(\{a_i, a_{i+1},\dots, a_n\}\) 为 multitest.

Data: \(T\leq 300000\), \(2 \leq n\leq 300000\), \(\sum n_i\leq 30000\).

Solution: 【dp】

Observation 1: 答案只可能是 \(0,1,2\), 这一点可以从样例得到启发。原因是只需要修改第一个数为 \(1\), 第二个数为 \(n-2\) 则一定可以使其成为 multitest;

Observation 2: 判断为 \(0\) 是容易的,从后往前考虑,同时维护链(test)是否能覆盖完整个序列,如果可以,计算链的长度。假如可以覆盖并且 \(a_i\) 等于test的个数, 那么答案为 \(0\).

Observation 3: 现在只需要考虑何时为 \(1\).

​ (1) 可以覆盖,则只需更改第一个数为test数量;

​ (2) 不能覆盖,那么只需求出最大可能的test数,小于该值的也一定可行,因为可以修改第二个值,使得其多覆盖任意多个test。那么问题变为如何计算修改一次后最大可能的test数。考虑 dp,如果修改第二个数,test数量为之后可覆盖的最长链+1;如果不修改第二个数,答案为 dp[a[i] + i + 1] + 1.取 max 即可。和第一个数比较大小,若第一个数小于等于这个数,那么答案为 \(1\),否则为 \(2\).

Review: -

State: AC.

Code:

#define Justanaaaaame
#include <iostream>
#include <cstring>
using namespace std;

#define MAXN 300010
int a[MAXN];
int go[MAXN];
bool able[MAXN];
int len[MAXN];
int dp[MAXN];   // 第 i 位后修改1次的最长链
int ans[MAXN];

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        memset(able, 0, sizeof(bool) * (n+5));
        memset(len, 0, sizeof(int) * (n+5));
        memset(dp, 0, sizeof(int) * (n+5));
        for (int i = 1 ; i <= n ; ++i)
        {
            cin >> a[i];
            go[i] = i + a[i] + 1;
            if (go[i] > n + 1)
                go[i] = n + 2;
        }
        able[n + 1] = true;
        int maxlen = 0;    
        for (int i = n ; i ; --i)
        {
            able[i] = able[go[i]];
            len[i] = len[go[i]] + 1;
            if (able[i])
                maxlen = max(maxlen, len[i]);
            dp[i] = max(dp[go[i]] + 1, maxlen + 1);
        }
        for (int i = n - 1 ; i ; --i)
        {
            if (able[i + 1])
            {
                if (a[i] == len[i + 1])
                    ans[i] = 0;
                else
                    ans[i] = 1;
            }
            else
            {
                if (dp[i + 1] >= a[i])
                    ans[i] = 1;
                else
                    ans[i] = 2;
            }
        }
        for (int i = 1 ; i < n ; ++i)
            cout << ans[i] << ' ';
        cout << '\n';
    }

}

F|Gifts from Grandfather Ahmed

State: 咕咕咕

标签:cout,int,860,Codeforces,cin,leq,MAXN,Div,define
From: https://www.cnblogs.com/Justanaaaaame/p/17300266.html

相关文章

  • Codeforces Round 864 (Div. 2)
    评价:A~E感觉出的挺一般,特别是D怎么放这种暴力题,场上我还没调出来,F没看。但是Orzrui_er。A在一个点周围放障碍即可。B求出最少需要的操作次数\(p\),若\(p>k\)就无解,否则若\(n\)为偶数只能任选一个格子翻偶数次,即有解当且仅当\(2\mid(k-p)\);若\(n\)为奇数可......
  • Edu Round 板刷计划 4. Educational Codeforces Round 4 题解
    ChangeLog:2023.04.06开坑.A-TheTextSplitting弱智题.枚举分出来多少个长度为\(p\)的串,则能计算出长度为\(q\)的串有多少个,若合法则直接输出即可.无解输出-1.Samplesubmission.B-HDDisOutdatedTechnology比A还弱智.直接记录每个数的位置,然后模拟一......
  • codeforces 1804D Accommodation
    https://codeforces.com/problemset/problem/1804/D解题思路每个楼层是独立的,考虑怎么解决一层就可以了。求最大值就是尽量避免1和1合并,也就是尽量在不存在连续1的子序列中进行合并,如果还有需要合并的就只能用1和1合并。求最小值就是尽量合并1和1。由于只需要输出最大最小值,所......
  • Educational Codeforces Round 146 (Rated for Div. 2)
    A.Coins#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongintread(){intx=0,f=1,ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch......
  • Educational Codeforces Round 124 (Rated for Div. 2)
    题目链接C核心思路其实还是得根据样例,首先我们先自己分析出来。现根据边地数目来分析。我们其实不难发现四个端点必须得连上边。边数为2.那么只有两条竖线。方案数是一种边数为3,那么就一条竖线还有就是一把叉这里交换位置就是两条了。还有就是平行四边形和一条斜线,也是可以......
  • [CodeForces]4.7
    题目链接:https://codeforces.com/contest/1610/problem/E灵神描述输入t(≤1e4)表示t组数据。所有数据的n之和≤2e5。每组数据输入n(2≤n≤2e5)和长为n的有序数组a(1≤a[i]≤1e9),有重复元素。你需要从a中删除一些元素,对于a的任意非空子序列b,都必须满足:设avg为......
  • UVA - 562 Dividing coins 经典01背包
    题目大意:给出一系列硬币,要求分给两个人,且两个人得到的硬币差达到最小值解题思路:用d[i]表示i这个数是否能被表示,则如果d[i-num[j]]==1的话,num[j]表示硬币的价值,则d[i]就可以被表示,最后只要判断sum>>1然后递减到0的期间遇到哪个数字能表示的,能表示的话就找到结果了,结果为sum-2*i,具体......
  • CodeForces - 149D Coloring Brackets(区间DP)
    题目大意:给你一个符合括号规则的字符串,现在要求你将这些括号染色,染色规则如下1.一个括号要么被染成红色,要么被染成蓝色,要么不染2.相邻的括号的颜色不能相同(可以同为无色)3.成对的括号只能有一个被染色问染色的方案数解题思路:0表示不染,1表示红色,2表示蓝色那么成对的括号......
  • LinearLayout增加divider分割线
    在android3.0及后面的版本在LinearLayout里增加了个分割线android:divider="@drawable/shape"<!--分割线图片-->android:showDividers="middle|beginning|end"<!--分割线位置-->分割线如果是图片那就直接使用图片就行,如果要使用颜色就必须使用shape来显......
  • codeforces 1793D Moscow Gorillas
    https://codeforces.com/contest/1793/problem/D解题思路依次找出MEX=1..n+1的序列数量就能得解。MEX=n+1只有全序列这一种情况。MEX=1时,找出两个序列中1的位置,较小位置左边的元素构成的子序列,较大位置右边的元素构成的子序列,以及两个位置中间的元素构成的子序列都满......