codeforces #402

A. Pupils Redistribution

题意:给2行数字,问最少第一行与第二行交换次数,使得第一行所有数字的出现次数等于第二行,如做不到相同输出-1。

thinking:直接2行的每个数字相加,判断其%2是否等于0,如果不等则输出-1。

然后把所有2行的次数差的绝对值相加,用总绝对值/4即可。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
int q1[6];
int q2[6];
int main(){
    //freopen("in.txt","r",stdin);
    int i,j,k,f1,f2,f3,t1,t2,t3,n,m;
    scanf("%d",&n);
    memset(q1,0,sizeof(q1));
    memset(q2,0,sizeof(q2));
    int sum1=0;
    int sum2=0;
    for(i=1;i<=n;i++){
        scanf("%d",&t1);
        q1[t1]++;
        }
        for(i=1;i<=n;i++){
            scanf("%d",&t2);
            q2[t2]++;
        }
        if((q1[1]+q2[1])%2!=0||(q1[2]+q2[2])%2!=0||(q1[5]+q2[5])%2!=0||(q1[3]+q2[3])%2!=0||(q1[4]+q2[4])%2!=0){
            cout << "-1" << endl;
        }else{
        sum1=abs(q1[1]-q2[1])+abs(q1[2]-q2[2])+abs(q1[3]-q2[3])+abs(q1[4]-q2[4])+abs(q1[5]-q2[5]);
        cout << sum1/4 << endl;
        }

    return 0;
}


B. Weird Rounding

题意:给一串数字,和一个数字K,问这串数字最少去掉几个(digit)也就是位数,可以让其(divisible)整除by 10^k,注意0可以整除任何数,但是必须将这串数字删除到只剩下一个0,如果2个0的值是不能计算为一个0的,给的数字确保是能整除的。

thinking:判断这串数字的长度是否大于k,如果不大于直接输出(长度-1)也就是0,如果大于k,那么从这串数字的右边i=0开始,找0的个数等于k时的那个i的值,然后输出(i+1)-k,如果找不到0个数等于k,则直接输出(长度-1)。

the reason of failure:1、范围特例,没有考虑到N可以为0这个特殊情况。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
int qq[15];
int main(){
    //freopen("in.txt","r",stdin);
    int i,j,k,f1,f2,f3,t1,t2,t3,n,m;
    long long c1,c2,c3;
    memset(qq,0,sizeof(qq));
    cin >> c1 >> k;
    c3=c1;
 //   c2=pow(10,k);
    t1=1;
    n=0;
    while(c3){
        qq[t1++]=c3%10;
        c3=c3/10;
        n++;   //n位数
    }
    if(n>k){
            f1=0;f2=0;
        for(i=1;i<=n;i++){
            if(qq[i]==0)f1++;
            if(f1==k){   //0的数量够
                f2=i-k;
                cout << f2 <<endl;
                return 0;
            }
        } //如果0的数量不够,那就只留下只有1个0
                cout << n-1 <<endl;
            return 0;
    }else{ //如果位数小于 也是留下一个0
        if(c1==0)
            cout << 0 << endl;
        else
            cout << n-1 <<endl;
    }

    return 0;
}

C. Dishonest Sellers

题意:给2个数字N和K,分别表示要买N件商品和第一次购物至少要买K件商品,然后给2行每行均有N个数字,分别表示第N件在第一次购物与第二次购物的价格,

第二次购物的价格并不一定比第一次低,问买N件商品最小花费。

thinking :第一次全部购物的总价格为sum1,然后循环一遍第二次购物价格低于第一次的商品个数t1,并把第一次-第二次的价格差重新放到一个数组中,然后排序,判断是t1大还是N-K大,如果是t1大,那么应尽量买降价的商品,也就是用sum1-降价最多的N-K件商品,如果是N-K大,则第二次只把t1件降价的商品买了,也就是sum1-t1件降价商品的总降价金额。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int q1[200500];
int q2[200500];
int q3[200500];
int main(){
    //freopen("in.txt","r",stdin);
    int i,j,k,f1,f2,f3,t1,t2,t3,n,m;
    long long c1,c2,c3;
    memset(q1,0,sizeof(q1));
    memset(q2,0,sizeof(q2));
    memset(q3,0,sizeof(q3));
    scanf("%d%d",&n,&k);
    c1=0;
    for(i=1;i<=n;i++){
        scanf("%d",&q1[i]);
        c1+=q1[i];
    }
    t1=0;
    for(i=1;i<=n;i++){
        scanf("%d",&q2[i]);
        q3[i-1]=q1[i]-q2[i];
        if(q1[i]>=q2[i])t1++;
    }
    sort(q3,q3+n);
    //cout << c1 <<endl;
    //cout << n-k <<  "  " << t1 <<endl;
    if(t1>=n-k){   //有t1个是降价的
    for(i=1;i<=n-k;i++){ //买2个降价多的
        c1-=q3[n-i];
    }
    cout << c1 <<endl;
    }else{ //降价的较少,只买降价的
    for(i=1;i<=t1;i++){
        c1-=q3[n-i];
    }
    cout <<c1 << endl;
    }
    return 0;
}
D. String Game(逆向思维+二分)----二分不一定非得按照顺序才使用,查找都可以尝试用
题意:就是给2段字符串p,t,确保在顺序不变的情况刷,t可以由从p的一个个按顺序排字符组成,也就是ababcba里面有abb, 然后下一行一排数字,分别按照这些数字的顺序将这些数字一个个删除,问在保证t可以从p中找到的情况下,最多可以删除几个字符。

thinking:(看题解的)

做题的时候,题目一直看错,花了一个小时在瞎做,怪不得样例一直不过,后面剩的时间不多太慌了,

刚开始一直是想如何有更短复杂度的正向的查找方法,结果一直在O(N^2)的方法找不到更短了,然后想着正向找线性的方法,也没法,这种题应该换个打破常规用另外的方法去做的。

如例子

ababcba
abb
5 3 4 1 7 6 2
用qq[5]=1.qq[3]=2,qq[4]=3,qq[5]=4.表示第qq[n]为第n次删除,然后二分来找,l=0,r=strlen(p),while(r>l)mid=(l+r)/2+1,for由i开始也就是从第一个字符开始找,是从通过qq[i]的值大于mid(也就是第mid次删除)的提取出到一个新的数组里,这样是为了保证提取的字符顺序不乱,然后判断其是否能拼成t,如果不能,那么r=mid-1,如果能,那么l=mid,

这样可以找到r为最大值,也就是最多可以删除r个字符。

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
char q1[200500];
char q2[200500];
int qq[200500];
char q3[200500];
int q4[200500];
int main(){
    int i,j,k,l,f1,f2,f3,t1,t2,t3;
    //freopen("in.txt","r",stdin);
    memset(q1,0,sizeof(q1));
    memset(q2,0,sizeof(q2));
    memset(qq,0,sizeof(qq));
    memset(q3,0,sizeof(q3));
    memset(q4,0,sizeof(q4));
    scanf("%s",q1+1);
    scanf("%s",q2+1);
    int l1,l2;
    l1=strlen(q1+1);
    l2=strlen(q2+1);
    for(i=1;i<=l1;i++){ 
        scanf("%d",&qq[i]);
        q4[qq[i]]=i;
    }
    int r;
    l=0;r=l1;
    int mid;
    while(l<r){
        mid=(l+r)/2+1;
        t1=0;
        for(i=1;i<=l1;i++)if(q4[i]>mid){   //��ΧӦ����
                q3[++t1]=q1[i];   
    }
    t2=1;
    for(i=1;t2<=l2&&i<=t1;i++){  
        if(q3[i]==q2[t2])t2++;
    }
     if(t2>l2)l=mid;
        else r=mid-1;
    }
    cout << l << endl;
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值