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

Codeforces Round 917 (Div. 2)

时间:2024-02-04 22:45:58浏览次数:30  
标签:le int Codeforces sol -- x2 using 917 Div

https://codeforces.com/contest/1917

A. Least Product *800

给定整数数组,可以把数组中的数 \(a_i\) 改为 \(0\sim a_i\) 中的任意整数,最小化所有数的乘积,在此基础上使操作次数最少

讨论一下负数的个数和 \(0\) 的个数

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

void sol() {
    int n;
    cin >> n;
    bool zero = 0, neg = 0;
    while (n--) {
        int x; cin >> x;
        if (x < 0) neg ^= 1;
        if (x == 0) zero = true;
    }
    if (zero || neg) cout << "0\n";
    else cout << "1\n1 0\n";
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T; cin >> T; while (T--)
        sol();
}

B. Erase First or Second Letter *1100 还行的思维题

给定字符串,可以删除首字符(即第一个字符)和删除第二个字符任意次,问能得到的本质不同串个数。 \(n\le 10^5\)

删除后的串长这样(剩下6个字符):xxxxxx??????

或者这样:xxxxx?xxxxxxxx?????

也就是说长度相同的串只可能在第一个字符处不同

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

void sol() {
    int n;
    string s;
    cin >> n >> s;
    
    int ans = n;
    vector<int> cnt(26);
    for (char c : s) {
        for (int i = 0; i < 26; i++) {
            if (cnt[i] && c - 'a' != i) //前面的一个字符与当前字符不同
                ans++;
        }
        cnt[c - 'a']++;
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T; cin >> T; while (T--)
        sol();
}

C. Watering an Array *1600 比较无聊

有一个长度为\(n\)的整数数组 \(a\),无限循环数组 \(b\)(\(b=[v_1,v_2,\ldots,v_k,v_1,v_2,\ldots,v_k,\ldots]\))。

第 \(i\) 次操作你可以执行以下两种操作之一:

  • 将数组 \(a\) 的前 \(b_i\) 个元素的值都加 \(1\);
  • 计算使 \(a_j=j\) 成立的元素个数为 \(c\)。将 \(c\) 加到你的得分上,并将整个数组 \(a\) 的所有元素都置为 \(0\)

求 \(d\) 次操作后能获得的最大得分。

\(n\le 2000,k\le 10^5, k\le d\le 10^9, 1\le v_i\le n\)

我好像非常不擅长这种题。。。居然卡了很久

首次把数组清零后,不管怎么操作数组中的数都单调不增的,所以 \(c\) 至多为 \(1\)。

所以首次把数组清零后,理想的方案是交替进行两种操作,每两次操作使答案 \(+1\)。

枚举首次清零的时间即可。但是枚举到 \(n\) 是不够的!(wa了两发)

可以这样考虑:若交替进行两种操作,则答案增加的速度是 \(0.5\)。而如果在第 \(2n\) 次以后才进行首次操作二,最好的情况是使答案 \(+n\),答案增加的平均速度 \(<n/2n=0.5\),还不如早点开始交替。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 5;
ll n, k, d, a[N], v[N];
void sol() {
    cin >> n >> k >> d;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= k; i++) cin >> v[i % k];
    
    ll ans = 0;
    for (int i = 1; i <= min(d, n + n); i++) {
        ll res = 0;
        for (int j = 1; j <= n; j++) res += a[j] == j;
        ans = max(ans, res + (d - i) / 2);
        for (int j = 1; j <= v[i % k]; j++) a[j]++;
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T; cin >> T; while (T--)
        sol();
}

D. Yet Another Inversions Problem *2300 挺好的题

给定 \(1\sim 2n-1\) 中所有奇数的排列 \(p[]\) 和 \(0\sim k-1\) 的排列 \(q[]\),数组 \(a[]\) 定义为:\(a_{ik+j}=p_i\cdot 2^{q_j}\),求 \(a[]\) 的逆序对数。

\(n,k\le 2e5\)

\(p2^{q_0},p2^{q_1},\cdots ,p2^{q_k}\) 的逆序对数就是排列 \(q[]\) 的逆序对数,下文不考虑这种情况。

对于一个数 \(p2^{q}\),考虑位置在它之后的哪些数小于它:

  • \(x2^0,x2^1, \cdots, x2^{q-1}\) \(, x\in (p,2p)\)
  • \(x2^0,x2^1, \cdots, x2^{q-2}\) \(, x\in (2p,4p)\)
  • \(x2^0,x2^1, \cdots, x2^{q-3}\) \(, x\in (4p,8p)\)
  • \(\cdots\)

同样还有

  • \(x2^{0},x2^{1}, \cdots, x2^{q+1}\) \(, x\in (p/2,p)\)
  • \(\cdots\)

这样复杂度有点高。改为考虑某个 \(x\in (p,2p)\) 的贡献:

  • \(p2^{1}\) 与 \(x2^0\) 形成 \(1\) 个逆序对
  • \(p2^{2}\) 与 \(x2^0,x2^1\) 形成 \(2\) 个逆序对

这样完全可做,但可能不太好写。考虑枚举指数的差:

  • 形如 \(\{p2^q,x2^{q}\}\) 的逆序对,\(x\in(0,p)\),\(q\) 有 \(k\) 种取值
  • 形如 \(\{p2^q,x2^{q-1}\}\) 的逆序对,\(x\in(0,2p)\),\(q\) 有 \(k-1\) 种取值
  • 形如 \(\{p2^q,x2^{q+1}\}\) 的逆序对,\(x\in(0,p/2)\),\(q\) 有 \(k-1\) 种取值

这样好像好写一点点。树状数组维护一下

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int P = 998244353;

struct BIT {
    int n; vector<int> tr;
    BIT(int n): n(n), tr(n + 1) {}
    int lowbit(int x) { return x & -x; }
    void add(int p, int x) { for (; p <= n; p += lowbit(p)) tr[p] += x; }
    int ask(int p) { int s = 0; for (; p > 0; p -= lowbit(p)) s += tr[p]; return s; }
};

void sol() {
    int n, k;
    cin >> n >> k;
    vector<int> p(n), q(k);
    for (int &x : p) cin >> x;
    for (int &x : q) cin >> x;

    ll ans = 0;
    
    //行内逆序对
    BIT row(k);
    for (int i = k - 1; ~i; i--) {
        ans += row.ask(q[i] + 1);
        row.add(q[i] + 1, 1);
    }
    (ans *= n) %= P;
    
    //行间逆序对
    BIT tr(2 * n - 1);
    for (int i = n - 1; ~i; i--) {
        for (ll _k = k, _p = p[i]; _k; _k--, _p *= 2) {
            if (_p >= 2 * n - 1) { //越界了,直接等差数列
                (ans += _k * (_k + 1) / 2 % P * tr.ask(2 * n - 1) % P) %= P;
                break;
            }
            (ans += _k * tr.ask(_p)) %= P;
        }
        for (ll _k = k - 1, _p = p[i] / 2; _k > 0 && _p > 0; _k--, _p /= 2)
            (ans += _k * tr.ask(_p)) %= P;
        tr.add(p[i], 1);
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T; cin >> T; while (T--)
        sol();
}

E. Construct Matrix *2500 构造构造

给定偶数 \(n\) 和整数 \(k\),构造 \(01\) 矩阵,满足:共有 \(k\) 个 \(1\)、每行异或和相等、每列异或和相等。

若无法构造,输出 No

\(0\le k \le n^2\)

因为每行异或和相等且 \(n\) 为偶数,故所有数异或和为 \(0\),所以 \(k\) 为奇数时无解。下面讨论 \(k\) 为偶数的情况:

只有两个 \(1\) 或只有两个 \(0\),

  • \(k=2\) 或 \(k=n^2-2\),仅当 \(n=2\) 时有解

其他情况,

  • \(k=0,4,8,12,\cdots\),在任意空白处不断填 \(2\times 2\) 的全 \(1\) 矩阵,每行/列异或和始终是 \(0\)

  • \(k=6\),

    1 1 0 0
    1 0 1 0
    0 1 1 0
    0 0 0 0
    
  • $k=10,14,18,\cdots $,先把上面的矩阵取反,

    0 0 1 1
    0 1 0 1
    1 0 0 1
    1 1 1 1
    

    然后在旁边加 \(2\times 2\) 的全 \(1\) 矩阵,即可扩展到 \(n\) 为 \(\ge k\) 的任意偶数的情况,

    0 0 1 1 1 1
    0 1 0 1 1 1
    1 0 0 1 1 1
    1 1 1 1 1 1
    1 1 1 1 1 1
    
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void sol() {
    int n, k;
    cin >> n >> k;    
    
    bool ok = true;
    vector<vector<int>> a(n + 1, vector<int>(n + 1));
    
    if (k % 2) {
        ok = false;
    } else if (k == 2 || n * n - k == 2) {
        if (n == 2) a[1][1] = a[2][2] = 1;
        else ok = false;
    } else if (k % 4 == 0) {
        for (int i = 1; i <= n; i += 2)
            for (int j = 1; j <= n && k; j += 2)
                a[i][j] = a[i + 1][j] = a[i][j + 1] = a[i + 1][j + 1] = 1, k -= 4;
    } else if (k == 6) {
        for (int i = 1; i <= 3; i++)
            for (int j = 1; j <= 3; j++)
                if (i + j != 4) a[i][j] = 1;
    } else {
        for (int i = 1; i <= 4; i++)
            for (int j = 1; j <= 4; j++)
                if (i + j == 4 || i == 4 || j == 4) a[i][j] = 1;
        k -= 10;
        for (int i = 1; i <= n; i += 2)
            for (int j = 1; j <= n && k; j += 2)
                if (i > 4 || j > 4)
                    a[i][j] = a[i + 1][j] = a[i][j + 1] = a[i + 1][j + 1] = 1, k -= 4;
    }
    
    if (!ok) cout << "No\n";
    else {
        cout << "Yes\n";
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                cout << a[i][j] << " \n"[j == n];
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T; cin >> T; while (T--)
        sol();
}

F. Construct Tree *2500 bitset优化01背包

给定 \(n\) 条边的边权,用全部边构造一棵树,要求直径为 \(d\)

\(n\le 2000,d\le 2000\)

这种题目一般都是先弄出直径来,然后把其他边挂到某点上。

所有边按从小到大排序,记为 \(l_1,l_2,\cdots, l_n\)

如果能找出若干条边,边权之和为 \(d\),且包含 \(l_n\) 在内,那就把它们作为直径,\(l_n\) 放在一端,其他的边这样接:

image

如果 \(l_n\) 与某条红边构成直径则无解。实际上,若 \(l_n+l_{n-1}> d\) 则无解,因为肯定存在过他们俩的边,使直径 \(>d\)。

否则如下图这样构造,绿边的边权和小于等于 \(l_n\),蓝边的边权和也小于等于 \(l_n\),且绿边的边权和加上蓝边的边权和等于 \(d\)。

image

背包,\(g[i][j][k]=True/False\) 表示在前 \(i\) 条边中选,蓝边的边权和为 \(j\),绿边的边权和为 \(k\) 是否合法。复杂度 \(O(nd^2)\)。绝望之中想起bitset优化,复杂度除以 \(32\),能过。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2010;
void sol() {
    int n, d;
    cin >> n >> d;
    vector<int> l(n);
    for (int &x : l) cin >> x;
    sort(l.begin(), l.end());
    
    if (l[n - 1] + l[n - 2] > d) return cout << "No\n", void();
    
    bitset<N> f;
    f[0] = 1;
    for (int i = 0; i < n - 1; i++)
        f |= f << l[i];
    if (f[d - l[n - 1]]) return cout << "Yes\n", void();
    
    vector<bitset<N>> g(d + 1);
    g[0][0] = 1;
    for (int i = 0; i < n; i++) {
        for (int j = d; ~j; j--) {
            if (j >= l[i]) g[j] |= g[j - l[i]] | (g[j] << l[i]);
            else g[j] |= g[j] << l[i];
        }
    }
    for (int i = l[n - 1]; d - i >= l[n - 1]; i++) {
        if (g[i][d - i]) return cout << "Yes\n", void();
    }
    cout << "No\n";
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T; cin >> T; while (T--)
        sol();
}

标签:le,int,Codeforces,sol,--,x2,using,917,Div
From: https://www.cnblogs.com/wushansinger/p/18007143

相关文章

  • left 3 Codeforces Round 913 (Div. 3)
    题目链接A.把同行同列除了起点都输出即可#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=2e5+10;voidsolve(){charc;inta;cin>>c>>a;for(inti=1;i<=8;i++){if(i==a)continue;cout<<c<......
  • CodeCraft-22 and Codeforces Round 795 (Div. 2)C. Sum of Substrings(分类讨论、贪
    感觉分类讨论的能有点弱。遇到复杂一点的分类讨论的题目,代码就写的巨长。首先观察到处在中间位置的1对答案的贡献是11,具体在中间哪个位置是没有关系的。只有两端的两个位置是比较特殊的\(1位置处的1对答案的贡献是10\)\(2位置处的1对答案的贡献是1\)所有我们考虑将最左端第一......
  • SMU Winter 2024 div2 ptlks的周报Week 2(1.29-2.4)
    这周学习到的知识点有斯特林数(F鸡数题!)F鸡数题!思路第二类斯特林数代码#include<bits/stdc++.h>#defineintlonglong#defineMOD1000000007usingnamespacestd;intn,m,f[100005],fi[100005];intqpow(inta,intn){ intans=1; while(n){ if(n&1){ ......
  • CodeForces 1918E ace5 and Task Order
    洛谷传送门CF传送门世纪难题。首先我们考虑先固定\(x\),比如让\(x=a_1\)(重复问\(1\)直到回答为=),那么此时我们可以知道任意一个\(a_i\)和\(a_1\)的大小关系(问一次\(i\)再问一次\(1\)),并且可以知道\(a_i\)的具体值。那么剩下的数被分成了两个集合,一个\(<a_1\)......
  • left 2 Codeforces Round 916 (Div. 3)
    题目链接A.遍历字符串,用map记录下每个字符出现的次数最后遍历26个字母,若出现了相应次数答案+1#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;voidsolve(){intn;cin>>n;strings;cin>>s;map<char,int>mp;......
  • 【解题报告】CodeForces523D:Statistics of Recompressing Videos
    CF523D解题报告CF523D先上结果:前两次语言选错了,编译一直不过(做这题是因为集训老师让我做我就做了,要不然我都快忘了我有CF账号了(思路省流:STL大法开一个小根堆存目前正在运行的服务器(也可以大根堆,但是存时间进去的时候存负的),如果有空机就直接处理,这个视频处理完的时间就......
  • Codeforces Round 734 (Div. 3)B2. Wonderful Coloring - 2(贪心构造实现)
    思路:分类讨论:当一个数字出现的次数大于等于k,那么最多有k个能被染色,当一个数字出现的次数小于k,南那么这些数字都可能被染色还有一个条件就是需要满足每个颜色的数字个数一样多,这里记出现次数小于k的所有数字的出现次数总和为sum,将所有这些数字排序后,前sum-sum%k个数字是都可以......
  • Codeforces Round 919 (Div. 2)
    A一笔带过,维护可能的最大值和最小值,并对于3操作特殊维护一下即可。B枚举第一个人删多少个数(贪心的想,一定删最大的几个,因为假如留着一定会对第二个人有利)第二个人一定是翻的越多越好,且翻的都是最大的几个数。使用前缀和容易计算答案。C妙妙题。枚举\(k\),接着发现\(a_i......
  • Codeforces Round 799 (Div. 4)G. 2^Sort
    暴力枚举每一个端点然后去check显然是复杂度为\(O(n^2)\)是来不及的。我们考虑大区间满足小区间一定满足,用两个指针维护一下当前满足不等式的区间,然后长度达到就计算答案。思路很简单,主要是这类双指针的题目里面的一些细节需要注意为了更好写我们总是先维护区间然后再计算答......
  • react 点击按钮 div隐藏显示 添加展开收起动画效果
    js代码const[collapse,setCollapse]=useState(false)  const[showBack,setShowBack]=useState(false)  constchangeCollapse=()=>{//获取展开收起目标元素    constheaderDes=document.querySelector('.phone_header_des');  ......