Codeforces Round 1020 (Div. 3)(题解ABCDEF)

A. Dr. TC

有n次翻转,从1到n,0->1,1->0,每次统计1的数量,设cnt1是字符串1的数量,n次就是n*cnt1,

但每个1都会被翻转一次减去一个cnt1,再统计cnt0,每个被翻转一次,答案就是(n-1)*cnt1+cnt0

cpp 复制代码
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{
    int n;cin>>n;
    string s;cin>>s;
    int cnt1=0,cnt0=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='1')cnt1++;
        else cnt0++;
    }
    cout<<(n-1)*cnt1+cnt0<<endl;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;cin>>t;
	while (t--)
	{
		solve();
	}
	return 0;
}

B. St. Chroma

给一个排列,从1到n依次做mex操作,让x出现次数最多 ,要出现x,要先排0~x-1,再放x后面的数字,最后再放x

cpp 复制代码
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{
    int n,x;cin>>n>>x;
    vector<int>ans(n);
    for(int i=0;i<x;i++)ans[i]=i;
    for(int i=x;i<n-1;i++)ans[i]=i+1;
    ans[n-1]=x==n?x-1:x;
    for(int i=0;i<n;i++)cout<<ans[i]<<" ";
    cout<<endl;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;cin>>t;
	while (t--)
	{
		solve();
	}
	return 0;
}

C. Cherry Bomb

给出a和b数组,当对应和都相等,就是互补数组,b中有缺失,求方案数

先找无解,那就是给出的对应和有多个 ,或凭借b的范围无法凑出对应和

有解的话就是1个,或b全是-1,有多个,找a的最小值与最大值,即可求

cpp 复制代码
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{
    int n,k;cin>>n>>k;
    ll maxx=-2,minn=1e18;
    ll sum=-1;
    vector<ll>a(n+1),b(n+1);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        maxx=max(maxx,a[i]);
        minn=min(minn,a[i]);
    }
    bool tag=true;
    for(int i=1;i<=n;i++)
    {
        cin>>b[i];
        if(b[i]!=-1)
        {
            if(sum==-1)sum=a[i]+b[i];
            else
            {
                if(a[i]+b[i]!=sum)tag=false;
            }
        }
    }
    if(!tag)
    {
        cout<<0<<endl;
    }
    else if(sum!=-1)
    {
        bool flag=true;
        for(int i=1;i<=n&&flag;i++)
        {
            if(b[i]==-1)
            {
                if(a[i]+k<sum||a[i]>sum)flag=false;
            }
        }
        if(flag)cout<<1<<endl;
        else cout<<0<<endl;
    }
    else
    {
        ll up=minn+k;
        if(up<maxx)cout<<0<<endl;
        else cout<<up-maxx+1<<endl;
    }
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;cin>>t;
	while (t--)
	{
		solve();
	}
	return 0;
}

D. Flower Boy

在a中找出一个长为m的序列,让对应ai都大于bi,也可删去b中一个再找

不操作有解直接输出

操做的话,考虑枚举删去的b,对a做前缀和与后缀和,pre[i]表示前i个元素可匹配b中前多少个,suf[i]同理

枚举b的过程中,到i,表示要找i-1个先匹配,再找n-i个在后面匹配,二分pre数组,看suf是否合法

cpp 复制代码
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{
    int n,m;cin>>n>>m;
    vector<ll>a(n+1),b(m+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++)cin>>b[i];
    int pos=1;
    for(int i=1;i<=n;i++)
    {
        if(pos!=m+1&&a[i]>=b[pos])pos++;
    }
    if(pos==m+1)
    {
        cout<<0<<endl;
        return;
    }
    vector<int>pre(n+1,0),suf(n+3,0);
    int t=1;
    for(int i=1;i<=n;i++)
    {
        int k=0;
        if(a[i]>=b[t])t++,k=1;
        pre[i]=pre[i-1]+k;
    }
    //for(int i=1;i<=n;i++)cout<<pre[i]<<" ";
    //cout<<endl;
    t=m;
    for(int i=n;i>=0;i--)
    {
        int k=0;
        if(a[i]>=b[t])t--,k=1;
        suf[i]=suf[i+1]+k;
    }
    ll ans=1e18;
    for(int i=1;i<=m;i++)
    {
        int pos=lower_bound(pre.begin(),pre.end(),i-1)-pre.begin();
        //cout<<pos<<endl;
        if(pos>n)continue;
        if(pre[pos]==i-1&&suf[pos+1]>=m-i)ans=min(ans,b[i]);
    }
    if(ans==1e18)cout<<-1<<endl;
    else cout<<ans<<endl;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;cin>>t;
	while (t--)
	{
		solve();
	}
	return 0;
}
/*
2
5 5
7 7 6 7 7
7 7 7 7 7
*/

E. Wolf

给出一个排列,有q次询问,询问l到r中能否二分到x,不可输出-1,可的话找最小操作数

可做的操作是对数组除x以外的数任意调换顺序,找调换顺序的最小个数

可用st数组记录每个元素的位置

#1.当mid<st[x],且p[mid]>x需要操作,将p[mid]换成小于x的

#2.当mid>st[x],且p[mid]<x需要操作,将p[mid]换成大于x的

注意到1与2,之间可以直接交换使其都合法

模拟二分过程,记录mid>x的次数,和mid>x并且合法次数

记录mid<x次数,和mid<x合法次数

于是就得到了mid<x与>x的不合法次数,抵消到有剩余,判断剩余的有没有对应剩余的可抵消

cpp 复制代码
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{
    int n,q;scanf("%d%d",&n,&q);
    vector<int>p(n+1),st(n+1);
    for(int i=1;i<=n;i++)
    {
        cin>>p[i];
        st[p[i]]=i;
    }
    vector<int>ans;
    while(q--)
    {
        int l,r,x;scanf("%d%d%d",&l,&r,&x);
        if(st[x]<l||st[x]>r)
        {
            ans.push_back(-1);
            continue;
        }
        if(l==r)
        {
            if(p[l]==x)ans.push_back(0);
            else ans.push_back(-1);
            continue;
        }
        int L=0,R=0,LL=0,RR=0;
        while(l<r)
        {
           int mid=(l+r)/2;
           if(p[mid]==x)break;
           if(mid<st[x])
           { 
               L++;
               if(p[mid]<x)LL++;
               l=mid+1;
           }
           else
           {
               R++;
               if(p[mid]>x)RR++;
               r=mid-1;
           }
           //cout<<l<<endl;
        }
        //cout<<l<<" "<<r<<endl;
        //cout<<cnt<<" "<<ok<<endl;
        if(L>x-1||R>n-x)ans.push_back(-1);
        else
        {
            L-=LL;
            R-=RR;
            if(L>=R)
            {
               ll tmp=L-R;
               if(x-1>=tmp+LL+R)ans.push_back(2ll*R+2ll*(L-R));
               else ans.push_back(-1);
            }
            else
            {
               ll tmp=R-L;
               if(n-x>=tmp+RR+L)ans.push_back(2ll*L+2ll*(R-L));
               else ans.push_back(-1);
            }
        }
    }
    for(auto y:ans)printf("%d ",y);
    printf("\n");
}
int main()
{
	int t = 1;scanf("%d",&t);
	while (t--)
	{
		solve();
	}
	return 0;
}
/*
3
13 1
12 13 10 9 8 4 11 5 7 6 2 1 3
1 13 2
*/

F. Goblin

与a题共享题面,但问的不同,n次操作后,我们需要找出这n*n的方格中 最大连通0的数量

考虑dp

注意到每次操作的数形成了主对角线

对于每个字符i,它在aii处翻转,其余保持不变

我们一列一列的添加,发现出现了四种状态转移

0->1,0->0,1->0,1->1

并且在一列一列添加的过程中,场上0的联通块数量不会大于2

因为如果s[i]是0,中间有1,其余为0,将其隔开有两个连通块,如s[i+1]是0,它的上连通块和下联通块会继承s[i]的

如果s[i+1]是1,一个0隔开上列1和下列1,它会将上连通块截止,继承上一个的下连通块

设置状态dp[i][0]表示到第i列,上连通块0的数量

dp[i][1]表示到第i列,下连通块0数量

cpp 复制代码
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{
    int n;cin>>n;
    string s;cin>>s;
    s="#"+s;
    vector<vector<ll>>dp(n+1,vector<ll>(2,0));
    if(s[1]=='0')dp[1][1]=n-1;
    else dp[1][1]=1;
    ll ans=0;
    for(int i=2;i<=n;i++)
    {
        if(s[i-1]=='0'&&s[i]=='1')
        {
            ans=max(ans,dp[i-1][0]);
            dp[i][1]=dp[i-1][1]+1;
        }
        else if(s[i-1]=='0'&&s[i]=='0')
        {
            dp[i][0]=dp[i-1][0]+i-1;
            dp[i][1]=dp[i-1][1]+n-i;
        }
        else if(s[i-1]=='1'&&s[i]=='0')
        {
            dp[i][0]=dp[i-1][1]+i-1;
            dp[i][1]=n-i;
        }
        else
        {
            ans=max(ans,dp[i-1][1]);
            dp[i][1]=1;
        }
    }
    ans=max(ans,dp[n][0]);
    ans=max(ans,dp[n][1]);
    cout<<ans<<endl;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t = 1;cin>>t;
	while (t--)
	{
		solve();
	}
	return 0;
}
相关推荐
yuanManGan1 小时前
C++入门小馆: 深入了解STLlist
开发语言·c++
梁下轻语的秋缘1 小时前
每日c/c++题 备战蓝桥杯(P1049 [NOIP 2001 普及组] 装箱问题)
c语言·c++·学习·蓝桥杯
逐光沧海2 小时前
STL常用算法——C++
开发语言·c++
wuqingshun3141592 小时前
蓝桥杯 5. 交换瓶子
数据结构·c++·算法·职场和发展·蓝桥杯
Demons_kirit2 小时前
Leetcode 2845 题解
算法·leetcode·职场和发展
球求了2 小时前
C++:继承机制详解
开发语言·c++·学习
adam_life2 小时前
http://noi.openjudge.cn/——2.5基本算法之搜索——200:Solitaire
算法·宽搜·布局唯一码
超爱笑嘻嘻3 小时前
shared_ptr八股收集 C++
c++
我想进大厂3 小时前
图论---朴素Prim(稠密图)
数据结构·c++·算法·图论
我想进大厂3 小时前
图论---Bellman-Ford算法
数据结构·c++·算法·图论