Codeforces Round #684 题解(A~C2)(待更新)

A. Buy the String

题目链接:A题

题目大意:
有一个01串,每个0的价格为c0,每个1的价格为c1,还可以花h元令串中某一个1变为0或0变为1,问买下这个01串最少要多少钱

分析:
签到题:
如果c0大于c1+h,就将所有的0变为1
如果c1大于c0+h,就将所有的1变为0
否则,不进行改变

代码:

#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
 
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
       int n,c0,c1,h;
       cin>>n>>c0>>c1>>h;
       string s;
       cin>>s;
       int n1=0,n2=0;
       for(int i=0;i<s.size();i++){
           if(s[i]=='0')   n1++;
           else n2++;
       }
       int ans;
       if(c0>c1+h)  ans=h*n1+s.size()*c1;
       else if(c1>c0+h)  ans=h*n2+s.size()*c0;
       else ans=n1*c0+n2*c1;
       printf("%d\n",ans);
    }
    return 0;
}

B. Sum of Medians

题目链接:B题

题目大意:
将median定义为一个长度为n的序列中[n/2](向上取整)的位置,现在给你一个长度为n*k的non-decreasing(非降)序列,让你将它拆成k个长度为n的序列,且要求这k个序列median位置上的元素值之和最大

分析:
贪心
将题目想象为从这个nk的序列中不断取出数字填充nk个格子:

假设n=4,k=3,则median=2
填充顺序应如下:
(序号表示在序列中的位置)
在这里插入图片描述
即:
①优先填充median位置前的格子
②然后填第一个序列的median位置
③填满第一个序列,这样能保证填下一个序列的median位置时数尽可能大
④填第二个序列的median位置
……

代码:

#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
 
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
       int n,k;
       scanf("%d%d",&n,&k);
       int median=(n+1)/2;
       int pos=(median-1)*k+1;
       int gap=n-median;
       long long ans=0;
       int t=0;
       for(int i=1;i<=n*k;i++){
            int temp;
            scanf("%d",&temp);
            if(i>=pos){
                t++;
                if(!gap||t%(gap+1)==1)
                  ans+=(long long)temp;
            }
       }
       printf("%lld\n",ans);
    }
    return 0;
}

C. Binary Table (Easy Version and Hard Version)

题目链接:easy versionhard version

题目大意:
给你一个大小为n×m的01矩阵
翻转规则:
每一次翻转,在矩阵中取一个2×2的小矩阵,令这个矩阵中任意三个元素01翻转(由0变为1或由1变为0)
求一个翻转方式使整个矩阵变为0
easy version要求翻转次数在3nm以内
hard version要求翻转次数在nm以内

分析:
观察一个2*2的小矩阵:
有1个1时需要3次翻转
有2个1时需要2次翻转
有3个1时需要1次翻转
有4个1时需要4次翻转

题目给的nm次数暗示了每个元素处理一次
我的考虑方式:
**从第1行到第n-1行:**在每一行只考虑将当前行的1翻转为0。分块操作:两两一组,让当前行的第1个与第2个元素为1组,第3与第4个元素为一组……因为每次操作可以任意翻转3个元素,所以我们可以做到将每一组的1在一次操作内都变为0,剩下的元素就在下一行中随意翻转。
这样我们处理完前n-1行最多只需要 ( n − 1 ) ⋅ m + 1 2 (n-1)\cdot\frac{m+1}{2} (n1)2m+1次操作
对于最后一行元素:
从第一个元素枚举到m-2个元素
以该元素为左下角建立一个22矩阵
对于每次操作的3个元素,我们优先把最后一行的元素1变为0,剩下两个元素我们对2
2矩阵中的右边两个元素进行翻转,因为这样子的话枚举到下个元素时,可以把这两个元素处理为0
因此枚举到第i个元素时
我们只需要保证将第i个元素和上一行的第i个元素变为0,剩下的就交给枚举到第i+1个元素时来进行就可以了
也就是说只需要m-2次操作就可以处理完最后一行的前m-2个元素
剩下最后四个元素:
也就是原矩阵右下角的四个元素,对于一个2*2的矩阵我们可以保证在4次操作内将其翻转完

这个思路我并没有严格证明是否满足mn次操作,在m和n比较大的时候显然时满足的,因为对于前n-1行的分块操作比较高效,而在m和n较小时我也没找到反例,故姑且认为是没问题的吧

代码:
我写的非常长且冗余。。。

#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;

typedef struct{
  int x[3];
  int y[3];
}operation;

int G[105][105];
operation op[30005];
int cnt=0;

int change(int x){
   if(x==1)  return 0;
   else return 1;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
       int n,m;
       cnt=0;
       scanf("%d%d",&n,&m);
       for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++){
            char temp;
            scanf(" %c",&temp);
            G[i][j]=temp-'0';
          }
       if(n*m>4)
       for(int i=1;i<n;i++)
           for(int j=1;j<m;j++){

                int temp=0;
                if(G[i][j]==0&&j!=m-1)  continue;
                if(G[i][j]==0&&j==m-1){
                    if(G[i][j+1]==0)  continue;
                    op[cnt].x[temp]=i,op[cnt].y[temp++]=j+1,op[cnt].x[temp]=i+1,op[cnt].y[temp++]=j, op[cnt].x[temp]=i+1,op[cnt++].y[temp]=j+1;
                    G[i][j+1]=change(G[i][j+1]),G[i+1][j]=change(G[i+1][j]),G[i+1][j+1]=change(G[i+1][j+1]);
                    continue;
                }


                op[cnt].x[temp]=i,op[cnt].y[temp++]=j,op[cnt].x[temp]=i+1,op[cnt].y[temp++]=j;
                 G[i][j]=change(G[i][j]),G[i+1][j]=change(G[i+1][j]);
                if(G[i][j+1]==1)
                    op[cnt].x[temp]=i,op[cnt++].y[temp]=j+1,G[i][j+1]=change(G[i][j+1]);
                else
                    op[cnt].x[temp]=i+1,op[cnt++].y[temp]=j+1,G[i+1][j+1]=change(G[i+1][j+1]);

       }

      for(int i=1;i<m-1;i++){
         int temp=0;
         if(G[n][i]==0&&G[n-1][i]==0)  continue;
         if(G[n][i]==1)  op[cnt].x[temp]=n,op[cnt].y[temp++]=i,G[n][i]=0;
         if(G[n-1][i]==1) op[cnt].x[temp]=n-1,op[cnt].y[temp++]=i,G[n-1][i]=0;
         op[cnt].x[temp]=n,op[cnt].y[temp++]=i+1;
         G[n][i+1]=change(G[n][i+1]);
         if(temp==2) op[cnt].x[temp]=n-1,op[cnt].y[temp++]=i+1,G[n-1][i+1]=change(G[n-1][i+1]);
         cnt++;
      }

       int x[4]={n,n,n-1,n-1};
       int y[4]={m,m-1,m,m-1};
       int num=0;
       for(int k=0;k<4;k++)
          if(G[x[k]][y[k]]==1)
                  num++;
        int temp=0;
          if(num==3){
              for(int k=0;k<4;k++)
                if(G[x[k]][y[k]]==1)
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                 cnt++;
              }
              if(num==2){
                 int fx,fy;
                 for(int k=0;k<4;k++)
                   if(G[x[k]][y[k]]==1){
                       fx=x[k],fy=y[k];break;
                  }
                  for(int k=0;k<4;k++)
                   if(!(x[k]==fx&&y[k]==fy))
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                  cnt++;
                  temp=0;
                  for(int k=0;k<4;k++)
                  if(G[x[k]][y[k]]==1)
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                 cnt++;

              }
              if(num==1){
                  int fx,fy;
                 for(int k=0;k<4;k++)
                   if(G[x[k]][y[k]]==0){
                       fx=x[k],fy=y[k];break;
                  }
                for(int k=0;k<4;k++)
                   if(!(x[k]==fx&&y[k]==fy))
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                  cnt++;
                  temp=0;
                for(int k=0;k<4;k++)
                   if(G[x[k]][y[k]]==1){
                       fx=x[k],fy=y[k];break;
                  }
                  for(int k=0;k<4;k++)
                   if(!(x[k]==fx&&y[k]==fy))
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                  cnt++;
                  temp=0;
                  for(int k=0;k<4;k++)
                  if(G[x[k]][y[k]]==1)
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                 cnt++;
              }
              if(num==4){
                  for(int k=0;k<3;k++)
                    op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                  cnt++;
                  temp=0;
                  int fx,fy;
                 for(int k=0;k<4;k++)
                   if(G[x[k]][y[k]]==0){
                       fx=x[k],fy=y[k];break;
                  }
                for(int k=0;k<4;k++)
                   if(!(x[k]==fx&&y[k]==fy))
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                  cnt++;
                  temp=0;
                for(int k=0;k<4;k++)
                   if(G[x[k]][y[k]]==1){
                       fx=x[k],fy=y[k];break;
                  }
                  for(int k=0;k<4;k++)
                   if(!(x[k]==fx&&y[k]==fy))
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                  cnt++;
                  temp=0;
                  for(int k=0;k<4;k++)
                  if(G[x[k]][y[k]]==1)
                     op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
                 cnt++;
              }


       printf("%d\n",cnt);


       for(int i=0;i<cnt;i++){
           for(int k=0;k<3;k++)
               k==0?printf("%d %d",op[i].x[k],op[i].y[k]):printf(" %d %d",op[i].x[k],op[i].y[k]);
           printf("\n");
       }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值