codeforces 545 1138 div2 解题报告 A/B/C/D

A

题意: 问你最长的 111222这样格式的子串有多长

题解:1112222211212  连续的数字转化为数量 352111 求一下相邻两个数字中小的那一个 最大是多少

#include <bits/stdc++.h>
#define maxn 100000+5
using namespace std;
int a[maxn];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d",&a[i]);
    vector<int>v;
    int flag=a[0],tmp=1;
    for(int i=1;i<n;i++){
        if(a[i]==flag){
            tmp++;
        }else {
            v.push_back(tmp);
            if(flag==1)flag=2;
            else flag=1;
            tmp=1;
        }
        if(i==n-1)v.push_back(tmp);
    }
    int ans=0;
    for(int i=0;i<v.size()-1;i++){
        ans=max(min(v[i],v[i+1]),ans);
    }
    cout<<ans*2<<endl;
    //while(1)getchar();
}

B

题意 第一排表示每个人能不能当小丑 第二排表示能不能演杂技

要求 将这些人分成两半 第一场表演当小丑的人数等于第二场演杂技的人数

输出哪些人 在第一场表演

题解:不太好想 定义c00 c10 c11 c01 为每个状态的人数

然后a00 a10 a01 a11为第一场 b00 b10 b01 b11为第二场表演的各个状态的人数

枚举 a10 a11 然后就能求出其他所有的状态 判断一下其他所有的状态是否合法

#include <bits/stdc++.h>
#define maxn 200000+5
using namespace std;
int main(){
    int c11=0,c10=0,c01=0,c00=0;
    string a,b;int n;
    cin>>n;
    cin>>a>>b;
    for(int i=0;i<n;i++){
        if(a[i]=='1'&&b[i]=='1')c11++;
        if(a[i]=='0'&&b[i]=='1')c01++;
        if(a[i]=='1'&&b[i]=='0')c10++;
        if(a[i]=='0'&&b[i]=='0')c00++;
    }
    int a00,a01,a10,a11,b00,b01,b10,b11;
    for(a10=0;a10<=c10;a10++){
        for(a11=0;a11<=c11;a11++){
            b10=c10-a10;
            b11=c11-a11;
            if(b11<0||b10<0)continue;
            b01=a10+a11-b11;
            if(b01<0||b01>c01)continue;
            a01=c01-b01;
            a00=n/2-a01-a10-a11;
            b00=c00-a00;
            if(a01<0||a01>c01||a00<0||a00>c00||b00+b10+b11+b01!=n/2||b00<0||b00>c00)continue;
            for(int i=0;i<n;i++)
			{
				if(a00&&a[i]=='0'&&b[i]=='0')printf("%d ",i+1),a00--;
				if(a01&&a[i]=='0'&&b[i]=='1')printf("%d ",i+1),a01--;
				if(a10&&a[i]=='1'&&b[i]=='0')printf("%d ",i+1),a10--;
				if(a11&&a[i]=='1'&&b[i]=='1')printf("%d ",i+1),a11--;
			}
            //while(1)getchar();
            return 0;
        }
    }
    printf("-1");
    //while(1)getchar();
    return 0;
}

C

题意 这个题的题意真的是。。。 对于每个路口的交点来说 ,竖排可以按照高低安排1-x 横排也是 (高低顺序不能变)

然后问你每个交点 对应的十字 最高的x是多大

输出矩阵

题解:将每个横排排序去重,竖排排序去重

然后找一下每个交点的高度 在横排里最高排大 竖排里最高排多大

和就是答案

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000+5
int a[maxn][maxn];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++)
            scanf("%d",&a[i][j]);
    }
    vector<int>r[maxn],c[maxn];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            r[i].push_back(a[i][j]);
        }
        sort(r[i].begin(),r[i].end());
        r[i].erase(unique(r[i].begin(),r[i].end()),r[i].end());
    }
    for(int j=0;j<m;j++){
        for(int i=0;i<n;i++){
            c[j].push_back(a[i][j]);
        }
        sort(c[j].begin(),c[j].end());
        c[j].erase(unique(c[j].begin(),c[j].end()),c[j].end());
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            int flag1=lower_bound(r[i].begin(),r[i].end(),a[i][j])-r[i].begin();
            int flag2=lower_bound(c[j].begin(),c[j].end(),a[i][j])-c[j].begin();
            int flag3=r[i].end()-lower_bound(r[i].begin(),r[i].end(),a[i][j]);
            int flag4=c[j].end()-lower_bound(c[j].begin(),c[j].end(),a[i][j]);
            printf("%d ",max(flag1,flag2)+max(flag3,flag4));
        }
        printf("\n");
    }
    //while(1)getchar();
    
    return 0;
}

D

题意 将第一个串重新排序 使得第二个串 在新生成的序列中出现次数最多

题解:注意是出现次数最多  所以出现的每一个子串是可以重叠的

不重叠直接输出就行了 一看到重叠我就想起了kmp

然后这个题就是kmp 求出next数组 找到最后一个字符输出完后应该跳到哪个字符继续输出

不难写,调试时间花费比较多

#include <bits/stdc++.h>
#define maxn 5000000+5
using namespace std;
int Next[maxn];
char t[maxn],s[maxn];
void getNext(char * p, int * Next)
{
	Next[0] = -1;
	int i = 0, j = -1;
    int ns=strlen(p);
	while (i < ns)
	{
		if (j == -1 || p[i] == p[j])
		{
			++i;
			++j;
			Next[i] = j;
		}	
		else
			j = Next[j];
	}
}
int main(){
    scanf("%s%s",t,s);
    getNext(s,Next);
    int n=strlen(t),t0=0,t1=0;
    for(int i=0;i<n;i++){
        if(t[i]=='0')t0++;
        else t1++;
    }
    int ns=strlen(s);
    /*for(int i=0;i<=ns;i++)
        cout<<Next[i];*/
    int flag=0;
    //cout<<endl;
    while(t0>0&&t1>0){
        if(flag==ns)flag=Next[flag];
        if(s[flag]=='1'){
            printf("1");
            t1--;
        }else {
            printf("0");
            t0--;
        }
        flag++;
    }
    while(t0>0)printf("0"),t0--;
    while(t1>0)printf("1"),t1--;
    //while(1)getchar();
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值