首页 > 其他分享 >CF Round 985

CF Round 985

时间:2024-11-11 17:00:50浏览次数:1  
标签:back int scanf CF 985 else erase include Round

比赛链接

A. Set

#include <iostream>
#include <cstdio>
using namespace std;
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",max(0,r/k-l+1));
    }
    return 0;
}

B. Replacement

操作就相当于删除R[i]^1
只要原序列S有0和1,那么肯定有相邻的地方。
反之,直接输出NO。
不用考虑具体删哪里,(实际上是删相邻的01之间的一个)无法删除了就是NO

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char str1[100005],str2[100005];
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int n;
        scanf("%d",&n);
        scanf("%s",str1);
        scanf("%s",str2);
        int len1=strlen(str1),len2=strlen(str2);
        int cnt1=0,cnt0=0;
        for(int i=0;i<len1;i++) {
            if(str1[i]=='1') cnt1++;
            else cnt0++;
        }
        if(cnt1==0||cnt0==0) {
            puts("NO");
            continue;
        }
        bool flag=1;
        for(int i=0;i<len2;i++) {
            if(str2[i]=='1') {
                if(!cnt1) {
                    flag=0;
                    break;
                }
                cnt0--;
            }
            else {
                if(!cnt0) {
                    flag=0;
                    break;
                }
                cnt1--;
            }
            if(cnt0<0||cnt1<0) {
                flag=0;
                break;
            }
        }
        puts(flag?"YES":"NO");
    }
    return 0;
}

C. New Rating

题意:选一段区间跳过,然后求最大rating
dp
f[i][0/1/2]分别表示当前到i,到i正在跳过/还没跳过/之前已经跳过 的最大rating
然后转移即可,详见代码。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=3e5+5;
int a[N];
int f[N][3];
//0跳,1没跳过,2跳过
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
        }
        f[1][0]=0;
        f[1][1]=1;
        // f[1][2]=0;
        if(n==1) {
            puts("0");
            continue;
        }
        for(int i=2;i<=n;i++) {
            f[i][0]=max(f[i-1][0],f[i-1][1]);
            if(a[i]>f[i-1][1]) 
                f[i][1]=f[i-1][1]+1;
            else if(a[i]==f[i-1][1])
                f[i][1]=f[i-1][1];
            else
                f[i][1]=f[i-1][1]-1;
            int tmp;
            if(a[i]>f[i-1][0]) tmp=1;
            else if(a[i]==f[i-1][0]) tmp=0;
            else tmp=-1;
            int tmp2;
            if(a[i]>f[i-1][2]) tmp2=1;
            else if(a[i]==f[i-1][2]) tmp2=0;
            else tmp2=-1;
            f[i][2]=max(f[i-1][0]+tmp,f[i-1][2]+tmp2);
            // cout<<f[i][0]<<" "<<f[i][1]<<" "<<f[i][2]<<endl;
        }
        printf("%d\n",max(f[n][2],f[n][0]));
    }
    return 0;   
}

D. Cool Graph

考试时的思路:
找所有的环,一只拆环直到不能拆,
随便找一条边作为基础,将拆出来的单独点,连到基础边上。
拆出来的几个联通块,想得是并查集维护(无敌麻烦)
但不太好处理找环和拆环。

看了题解:
找任意\(du[u]>=2\)的点u,再找它相邻的两个点,输出它们仨。
由于每个操作都会至少减少边数\(1\), 至多\(m\)次操作
一直重复,那么现在图上就不会再出现环了,被拆成了若干条链和独立点。
(这里就解决了前面的问题)
分开存链(边)和独立点。
对于独立点,随便找一条边(a,b)作为基础,将非(a,b)所在联通块的单独点,连到基础边上,注意基础边每次需要换,不能是同一条,要不就连成环了!
对于其他的边,和\(a\)连上就行。
这里至多\(max(n,m)\)次操作
总操作数\(<2*max(n,m)\)

具体实现:
每个点建一个set维护与他相邻的点,然后size就是其度数。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <vector>
#define LL long long
using namespace std;
const int N = 200005;
int n, m;
struct node {
    int a, b, c;
    node(int aa, int bb, int cc) {
        a = aa;
        b = bb;
        c = cc;
    }
    void print() {
        printf("%d %d %d\n", a, b, c);
    }
};
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n;
        scanf("%d %d", &n, &m);
        //init
        vector<set<int>> v(n + 1);
        vector<node> ans;
        for (int i = 1, x, y; i <= m; i++) {
            scanf("%d %d", &x, &y);
            v[x].insert(y);
            v[y].insert(x);
        }
        for (int i = 1; i <= n; i++) {
            while (v[i].size() >= 2) {
                int x = *v[i].begin();
                v[i].erase(x);
                int y = *v[i].begin();
                v[i].erase(y);
                v[x].erase(i);
                v[y].erase(i);
                ans.push_back(node(i, x, y));
                if (v[x].find(y) != v[x].end()) {
                    v[x].erase(y),
                            v[y].erase(x);
                } else {
                    v[x].insert(y);
                    v[y].insert(x);
                }
            }
        }
        vector<int> singlePoint;
        vector<pair<int, int>> p;
        for (int i = 1; i <= n; i++) {
            if (v[i].size() == 0) {
                singlePoint.push_back(i);
            } else if (*v[i].begin() > i) {
                p.push_back(make_pair(i, *v[i].begin()));
            }
        }
        if (p.size()) {
            auto [a, b] = p.back();
            p.pop_back();
            while (!singlePoint.empty()) {
                int x = singlePoint.back();
                singlePoint.pop_back();
                ans.push_back(node(x, a, b));
                b = x;//注意不能每次都合并到相同一条边,会成环,所以换个边
            }
            for (auto [x, y]: p) {
                ans.emplace_back(node(x, y, a));
            }
        }
        printf("%d\n", ans.size());
        for (auto x: ans) {
            x.print();
        }
    }
    return 0;
}

标签:back,int,scanf,CF,985,else,erase,include,Round
From: https://www.cnblogs.com/AuroraKelsey/p/18539675

相关文章

  • Codeforces Round 985 简略复盘
    A.Set题目描述给你一个正整数\(k\)和由\(l\)至\(r\)(含)的所有整数组成的集合\(S\)。您可以执行以下两步运算的任意次数(可能为零):首先,从集合\(S\)中选择一个数字\(x\),使得\(S\)(包括\(x\)本身)中至少有\(k\)个\(x\)的倍数;然后,从\(S\)中删除\(x\)(注意没......
  • 「杂题乱刷2」CF1219G
    题目链接CF1219GHarvester解题思路就是个嗯分讨题。发现最终选择的方案总共就以下五种情况:选\(4\)行\(0\)列。选\(3\)行\(1\)列。选\(2\)行\(2\)列。选\(1\)行\(3\)列。选\(0\)行\(4\)列。对于第一,五种情况,直接取每行或每列的前四大值......
  • Educational Codeforces Round 144 (Rated for Div. 2) C. Maximum Set
    我们要选出最长的子序列,使得每一个数都是前一个数的倍数。因此自然我们可以想到选择最小值然后每次乘\(2\)。所以有\(l\times2^k\ler\),即\(k=\left\lfloor\log_2\frac{r}{l}\right\rfloor\)。所以最大的集合大小就是\(k+1\)。然后考虑最大的集合中最小值可能不同,我假设......
  • CF 1257 题解
    CF1257题解ATwoRivalStudents每次交换都可以让距离增加\(1\),上界是\(n-1\).题目说至多而不是恰好交换\(x\)次,于是不需要考虑边界.BMagicStick一个重要的观察是:如果能够得到\(x\),那么就能得到任意小于等于\(x\)的数,这是操作二保证的.考虑操作\(1\)......
  • CF1821
    建议结合独立思考使用本题解。A没什么价值略去。B有一个序列\(a\),通过把它的一个子区间进行升序排序生成了\(b\)。现在给出\(a,b\),求出可以通过该操作使\(a\)变为\(b\)的最长子区间的左右端点,输出任意一个。\(n\le2\times10^5\)如果存在一个位置,使得\(a_{p}\neq......
  • Codeforces Round 983 (Div. 2) - A
    题目链接:https://codeforces.com/problemset/problem/2032/A题解代码:#include<bits/stdc++.h>usingnamespacestd;voidsolve(){intn;cin>>n;intcount0=0,count1=0;for(inti=0;i<n*2;i++){intx;......
  • 【题解】CF1993【EF】
    A注意到一种选项最多填对\(n\)个题所以答案是\(\min(n,cnt_a)+\min(n,cnt_b)+\min(n,cnt_c)+\min(n,cnt_d)\)B注意到操作只能让奇数变多,偶数变少,所以我们只能把偶数全变成奇数特判掉全是偶数的情况,容易得到答案下界:偶数个数容易想到一个naive贪心做法:每次都拿出奇数......
  • Sigrity SPEED2000 Power Ground Noise Simulation模式如何进行信号时域仿真操作指导(
    SigritySPEED2000PowerGroundNoiseSimulation模式如何进行信号时域仿真操作指导(一)-单个IBIS模型SigritySPEED2000PowerGroundNoiseSimulation模式如何进行信号时域仿真操作指导(一)-单个信号是用晶体管模型来作为驱动,下面以单个IBIS模型作为驱动来说明如何进行时......
  • Sigrity SPEED2000 Power Ground Noise Simulation模式如何进行信号时域仿真操作指导(
    SigritySPEED2000PowerGroundNoiseSimulation模式如何进行信号时域仿真操作指导(二)-三个信号SigritySPEED2000PowerGroundNoiseSimulation模式如何进行信号时域仿真操作指导(一)-单个信号详细介绍了单个信号的网络时域电压仿真,并且查看电压时域曲线,如果将信号扩展......
  • CF401
    A.VanyaandCardsCF原题链接题目大意:给出\(n\)个数\(a_{i}\),满足\(\lverta_{i}\rvert\leqslantx\),要求添加若干个满足以上要求的数,使得\(\Sigmaa_{i}=0\),求添加数字的最小数量\((1\leqslantn,x\leqslant1000)\)解题思路:直接做做完了。统计一下原本\(\Sigmaa_{i}\)的......