Codeforces Round #205 (Div. 2)

A - Domino
题意:给n个分数,x为分子,y为分母,问经过最少几次分子分母交换,得到分子之和和分母之和都为偶数。
思路:奇数+奇数=偶数,偶数+偶数=偶数,奇数+偶数=奇数。题目x,y范围也就1-6,自己模拟一下也ok.答案只有3种:
1,0,-1.因为只有奇偶两种情况,假设存在多个奇数,每次交换改变奇数个数,奇数个奇数之和为奇数,偶数个奇数之和为偶数.所以答案最大只能为1.
1.Σxy都为偶数,答案为0.
2.Σx,Σy一奇一偶的情况,答案为-1,
3.Σx,Σy都为奇数,那么就要判断是否分子分母为一奇一偶,若不是,则交换无意义,答案为-1.,反之,答案为1.
#include<bits/stdc++.h>
using namespace std;
int main(){
  int n,x,y,flag=0,sumup=0,sumlow=0;
  scanf("%d",&n);
  for(int i=0;i<n;i++){
    scanf("%d%d",&x,&y);
    sumup+=x;
    sumlow+=y;
    if(x%2&&y%2==0)flag=1;
    if(x%2==0&&y%2)flag=1;
  }
  if((sumup%2&&sumlow%2==0)||(sumup%2==0&&sumlow%2))
    printf("-1\n");
  else if((sumup%2==0&&sumlow%2==0))printf("0\n");
  else{
    if(flag)printf("1\n");
    else printf("-1\n");
  }

}
  B - Two Heaps
题意:给n个数,要求将这n个数分别分到2个不同的堆,从第一个堆取出一个数ab和第二个堆取出一个数cd组成数abcd,使得这个数不同的个数最多.给出分配方式.
思路:各个数都不相同,则一个一个分配是比较容易的.但若有某个数出现不止一次的则需要平均分配到两个堆.
#include<bits/stdc++.h>
using namespace std;
struct node{
  int b,id;
}num[205];
int ans[205],v[205];
bool cmp(node a,node b){
  return a.b>b.b;
}
int main(){
  int n,last,o,t;
  scanf("%d",&n);
  memset(num,0,sizeof(num));
  for(int i=1;i<=2*n;i++){
    scanf("%d",&num[i].b);
    num[i].id=i;
  }
  sort(num+1,num+2*n+1,cmp);
  last=2,t=o=0;
  memset(v,0,sizeof(v));
  for(int i=1;i<=2*n;i++){
    if(num[i].b==num[i+1].b){
      if(!v[num[i].b]){
        if(last==2){
          ans[num[i].id]=1;
          ans[num[i+1].id]=2;
          o++,t++;
          last=2;
        }
        else{
          ans[num[i].id]=2;
          ans[num[i+1].id]=1;
          o++,t++;
          last=1;
        }
        v[num[i].b]=v[num[i+1].b]=1;
      }
      else{
        if(last==2){
          ans[num[i+1].id]=1,last=1;
        }
        else ans[num[i+1].id]=2,last=2;
      }
    }
  }
  for(int i=1;i<=2*n;i++){
    if(!v[num[i].b]){
      if(last==2){
        ans[num[i].id]=1;
        o++;
        last=1;
      }
      else{
        ans[num[i].id]=2;
        t++;
        last=2;
      }
    }
  }
  printf("%d\n",t*o);
  printf("%d",ans[1]);
  for(int i=2;i<=2*n;i++){
    printf(" %d",ans[i]);
  }
  printf("\n");
}

写的有些繁琐,改进:
1.对于某个交替变换的变量,可用^运算符.
2.上面的t,o分别表示两个堆的不同数的个数,那么可以在输入的时候就判断该数的出现次数,若大于1的则在两个堆中都出现,若为1则只可能在某一个堆中.设出现次数大于1的数的个数有y个,出现次数等于1的有x个.
那么t*o=(y+x/2)*(y+x-x/2);
#include<bits/stdc++.h>
using namespace std;
int ans[205],v[205],a[205];
int main(){
  int n,x=0,y=0;
  scanf("%d",&n);
  memset(v,0,sizeof(v));
  for(int i=0;i<2*n;i++){
    scanf("%d",a+i);
    v[a[i]]++;
  }
  for(int i=10;i<=99;i++){
    if(v[i]>1)x++;
    if(v[i]==1) y++;
  }
  int z=(x+y),last=0;
  printf("%d\n",(y/2+x)*(y-y/2+x));
  for(int i=0;i<2*n;i++){
    if(v[a[i]]==1){
      ans[i]=last;
      last^=1;
    }
  }
  for(int i=10;i<=99;i++){
    if(v[i]>1){
      for(int j=0;j<2*n;j++){
        if(a[j]==i){
        ans[j]=last;
        last^=1;
        }
      }
    }
  }
  for(int i=0;i<2*n;i++){
    printf("%d ",ans[i]+1);
  }
}

C -Find Maximum
题意:给长度为n的数组a,长度为n的01字符串,m=,,求.f(x)的最大值.
思路:按照题目给的字符串的意思,倒置的二进制,00001=2^4,11110=1+2+2^2+2^3=2^4-1.我们先预处理数组sum[i]表示i之前的数组a的和.将字符串最后一个1开始往前循环,ans=max(ans,sum[i-1]),最后将ans和f(m)作比较取最大值.
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int a[MAX],sum[MAX];
char str[MAX];
int main(){
  int n;
  scanf("%d",&n);
  for(int i=0;i<n;i++){
    scanf("%d",a+i);
  }
  scanf("%s",str);
  sum[0]=a[0];
  for(int i=1;i<n;i++){
    sum[i]=sum[i-1]+a[i];
  }
  int j=n-1;
  while(str[j]=='0'){
    j--;
  }
  int orignal=0,ans=0;
  for(int i=j;i>=0;i--){
    if(str[i]=='1'){
      ans=max(ans,orignal+sum[i-1]);
        orignal+=a[i];
    }
  }
  printf("%d\n",max(orignal,ans));
}

D - Queue
题意:给一个MF的字符串,问至少需要几步才能把F全部移到左边,M全部移到右边.F可以移到左边为M,即MF->FM.
思路:MF->FM只需1步,MMFF->FFMM需要3步,原因是第二个F的前面是个F,需要第一个F先移动一步变得MFMF,然后第二个F才能移动.说明移动的步数除了和在F左边的M的个数有关,还和第一个F身后相邻的F个数有关.
#include<bits/stdc++.h>
using namespace std;
char str[1000005];
int main(){
  scanf("%s",str);
  int j=0,m=0,ans=0;
  while(str[j]=='F')j++;
  for(int i=j;i<strlen(str);i++){
    if(str[i]=='M')m++;
    else ans=max(ans+1,m);
  }
  printf("%d\n",ans);
}










  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值