Codeforces Round 874 (Div. 3)

这篇文章包含多个编程问题的解决方案,涉及字符串中两个字母的组合遍历、数组排序以及不同类型的算法应用。A部分展示了如何找到字符串中所有连续双字符的唯一组合;B部分实现了一个将数组按照指定顺序排列的功能;C部分讨论了如何通过贪心策略使所有偶数变为奇数或所有奇数变为偶数;D部分涉及找到排列的最大字典序;E部分利用并查集解决环状结构问题;F部分是关于滑动窗口和数组乘积的计算。
摘要由CSDN通过智能技术生成

A 直接遍历所有两个字母的字符串

import random
import sys
import os
import math
from collections import Counter, defaultdict, deque
from functools import lru_cache, reduce
from itertools import accumulate, combinations, permutations
from heapq import nsmallest, nlargest, heapify, heappop, heappush
from io import BytesIO, IOBase
from copy import deepcopy
import threading
import bisect

# from sortedcontainers import SortedList
BUFSIZE = 4096


class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = "x" in file.mode or "r" not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b"\n") + (not b)
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            self.buffer.truncate(0), self.buffer.seek(0)


class IOWrapper(IOBase):
    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode("ascii"))
        self.read = lambda: self.buffer.read().decode("ascii")
        self.readline = lambda: self.buffer.readline().decode("ascii")


sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout)
input = lambda: sys.stdin.readline().rstrip("\r\n")


def I():
    return input()


def II():
    return int(input())


def MI():
    return map(int, input().split())


def LI():
    return list(input().split())


def LII():
    return list(map(int, input().split()))


def GMI():
    return map(lambda x: int(x) - 1, input().split())


def LGMI():
    return list(map(lambda x: int(x) - 1, input().split()))




def solve():
    st=set()
    n=II()
    s=I()
    for i in range(0,n-1):
        p=s[i]+s[i+1]
        st.add(p)
    print(len(st))

# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':
    for _ in range(II()):
        solve()
# 访问 https://www.jetbrains.com/help/pycharm/ 获取 PyCharm 帮助

B 直接排序 小的对小的,大的对大的数

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include<functional>
using namespace std;
const int N = 2e5+10;

int n,m;
int a[N],b[N],id[N],res[N];
void solve(){
    cin>>n>>m;
    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++) id[i]=i;
    sort(id+1,id+1+n,[&](const int p,const int q){
        return a[p]<a[q];
    });
    sort(b+1,b+1+n);
    for(int i=1;i<=n;i++)
    {
        int x=id[i];
        res[x]=i;
    }
    for(int i=1;i<=n;i++)
    {
        cout<<b[res[i]]<<" ";
    }
    cout<<"\n";
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) solve();
}

C 贪心 让全部偶数变成奇数 或者全部奇数变成偶数 

偶数要减去最小的奇数变成奇数

奇数也要减去最小的奇数变成偶数

然后判断最后是否大于0即可

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include<functional>
using namespace std;
const int N = 2e5+10;

int n,m;
int a[N],b[N],id[N],res[N];
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    vector<int> odd,even;//奇数 偶数
    for(int i=1;i<=n;i++){
        if(a[i]&1) odd.push_back(a[i]);
        else even.push_back(a[i]);
    }
    sort(odd.begin(),odd.end());
    sort(even.begin(),even.end());
    bool f=true;
    if(odd.size()==0||even.size()==0){
       
        cout<<"YES\n";
        return ;
    }
    int mn=odd[0];
    for(auto x:odd)
    {
       
        if(x-mn<=0){
            
            f=false;
            break;
        }
    }
    if(f){
        cout<<"YES\n";
        return ;
    }
    mn=odd[0];
    f=true;
    for(auto x:even)
    {
        if(x-mn<=0){
            f=false;
            break;
        }
    }
    if(f){
        cout<<"YES\n";
        return ;
    }
    cout<<"NO\n";
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) solve();
}

首先贪心的想,字典序最大,因为是排列,所以最大数只有一个,所以贪心先让最大的数排在前面

然后有种情况最大的数在第一个,没办法只能找次大的

然后考虑最大数的左边一个数翻转是否继续往左边扩展

因为左边全部数最后都要放在后面,所以如果继续往左边扩展,那么新扩展的数最后就会成为后面第一个数,如果不扩展最后面的第一个数就是最左边的第一个数a[1]

所以可得如果a[l-1]>a[1]直接扩展即可

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 1e7+10;

int n,m;
int a[N];
void solve(){
    cin>>n;
    int id=0,mx=0;
    if(n==1){
        cin>>a[1];
        cout<<a[1]<<"\n";
        return ;
    }
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]>mx){
            mx=a[i];
            id=i;
        }
    }
    if(id==1){
        id=0,mx=0;
        for(int i=2;i<=n;i++){
            if(a[i]>mx){
                mx=a[i];
                id=i;
            }
        }
    }
    int l=id-1;
    if(id==n&&a[l]<a[1]){
        l=id;
    }
    else{
        while(l>1&&a[l-1]>a[1]) l--;
    }
    //cout<<l<<" "<<id<<"\n";
    for(int i=id;i<=n&&i>0;i++) cout<<a[i]<<" ";
    for(int i=id-1;i>=l&&i>0;i--) cout<<a[i]<<" ";
    for(int i=1;i<l&&i>0;i++) cout<<a[i]<<" ";
    cout<<"\n";
    
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;

    cin>>t;
    while(t--) solve();
}

E:首先最多的环直接并查集维护

最小情况的环就是把没确定两个邻居的点的所在环给合并

所以我直接拿了set判定点左右邻居是否重复且是否存在两个确定的邻居,只要环里面的邻居有一个点没确定就直接把他给合并

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include<functional>
using namespace std;
const int N = 2e5+10;

int n,m;
int a[N];
int p[N],sz[N];
set<int> st[N];
bool vis[N];
int find(int x)  // 并查集
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void solve(){
    cin>>n;
    for(int i=1;i<=n;i++) p[i]=i,sz[i]=1,st[i].clear(),vis[i]=false;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        st[i].insert(a[i]);
        st[a[i]].insert(i);
        int x=find(i),y=find(a[i]);
        if(x!=y){
            sz[y]+=sz[x];
        p[x]=y;
        }
    }
    int cnt0=0,cnt1=0;
    for(int i=1;i<=n;i++){
        if(st[i].size()<2&&!vis[find(i)]){
            cnt0++;vis[find(i)]=true;
        }
        if(find(i)==i) cnt1++;
    }
    cout<<min(cnt1,max(1,cnt1-cnt0+1))<<" "<<cnt1<<"\n";
    
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) solve();
}

F  

根据题目每两个数不能相同且最大和最小的数要严格小于m所以可以直接滑动窗口(不是0.0)

我直接维护了每个点直接的个数,直接找i到i-m+1的区间是否合法,贡献就是这个区间的人数相乘

就是Cx取1 =x ,然后除去不在这个区间的贡献(除法,mod-2懂我意思吧)

这里贴前缀和和滑动窗口的写法

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 2e5+10,mod=1e9+7;
typedef long long LL;

int n,m;
long long s[N];
int qmi(int a, int k, int p)  // 求a^k mod p
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

void solve()
{
    cin>>n>>m;
    map<int,int> mp;
    vector<int> a;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        mp[x]++;
        a.push_back(x);
    }
    a.push_back(-1);
    sort(a.begin(),a.end());
    a.erase(unique(a.begin(),a.end()),a.end());
    s[0]=1;
    for(int i=1;i<a.size();i++)
    {
        s[i]=(mp[a[i]]*s[i-1])%mod;
    }
    long long res=0;
    for(int i=1;i<a.size();i++)
    {
        int target=i+m-1;
        if(target<a.size()&&a[target]-a[i]<m)
        {
           // cout<<i<<" "<<target<<"\n";
           // cout<<s[target]%mod*max(1,qmi(s[i-1],mod-2,mod))%mod<<endl;
            res=(res+s[target]%mod*max(1,qmi(s[i-1],mod-2,mod)))%mod;
        }
            
    }
    cout<<res<<"\n";
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) solve();
}
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 2e5+10,mod=1e9+7;
typedef long long LL;

int n,m;
int qmi(int a, int k, int p)  // 求a^k mod p
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

void solve()
{
    cin>>n>>m;
    map<int,int> mp;
    vector<int> a;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        mp[x]++;
        a.push_back(x);
    }
    sort(a.begin(),a.end());
    a.erase(unique(a.begin(),a.end()),a.end());
    long long res=0;
    n=a.size();
    int l=0,r=0;
    long long cnt=1;
    while(r<n)
    {
        cnt=(cnt*mp[a[r]])%mod;
        while(a[r]-a[l]>=m)
        {
            cnt=(cnt*qmi(mp[a[l]],mod-2,mod))%mod;
            l++;    
        }    
        if(r-l+1>=m){
            res=(res+cnt)%mod;
        }
        r++;
    }
    cout<<res<<"\n";
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) solve();
}

G

直接贪心,每组成三个点直接分裂就行,存储的时候顺便记录边的id,如果组成不了就无解

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 2e5+10,M=2*N,mod=1e9+7;
typedef long long LL;
typedef pair<int, int> PII;
int n,m;
long long sz[N];
vector<PII> g[N];
bool cut[N];
vector<int> res;
bool flag;
int qmi(int a, int k, int p)  // 求a^k mod p
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}
void dfs(int u,int  fa){
    sz[u]=1;
    for(auto [j,id]:g[u]){
        if(j==fa) continue;
        dfs(j,u);
        if(sz[j]>3) flag=false;
        else if(sz[j]==3) res.push_back(id),sz[j]=0;
        else sz[u]+=sz[j],sz[j]=0;
        if(sz[u]>3) flag=false;
    }
}
void solve()
{
    cin>>n;
    res.clear();
   for(int i=1;i<=n;i++){
        g[i].clear();   
   }
   for(int i=1;i<n;i++){
       int a,b;
       cin>>a>>b;
       g[a].push_back({b,i});
       g[b].push_back({a,i});
   }
   flag=true;
   dfs(1,-1);
   if(!flag||sz[1]!=3)
   {
       cout<<"-1\n";
       return ;
   }
   cout<<res.size()<<"\n";
   for(auto&x:res) cout<<x<<" ";
   cout<<"\n";
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) solve();
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值