做了一套模拟contest,前三道题顺风顺水,第四道题卡懵逼了,不应该不应该。

A - Pupils Redistribution

题目大意:有两组,每组里面都有n个人,每个人都有一个评价分数1到5,你每次能从两组人中

分别挑选一个人,然后交换,问你使两组人每个分数评价的人都相同最少需要交换多少次。不能完成

输出-1。

 

思路:统计每组需要多少人需要到对面去,再除2就好了。

Codeforces Round #402 (Div. 2)_i++Codeforces Round #402 (Div. 2)_c++_02
#include<bits/stdc++.h>
using namespace std;
int vis[2][6];
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int g; scanf("%d",&g);
        vis[0][g]++;
    }
    for(int i=1;i<=n;i++)
    {
        int g; scanf("%d",&g);
        vis[1][g]++;
    }
    int ans=0;
    for(int i=1;i<=5;i++)
    {
        int sum=vis[1][i]+vis[0][i];
        if(sum&1)
        {
            puts("-1");
            return 0;
        }
        ans+=sum/2-min(vis[1][i],vis[0][i]);
    }
    if(ans&1) puts("-1");
    else cout<<ans/2<<endl;
    return 0;
}
View Code

 

B - Weird Rounding

题目大意:给你一个数n 和 一个数 k ,要求删除n中个位数中的某几个,使其能被 10^k 整除,问你

最少删除几个数。

 

思路:直接模拟,从最低位开始。

Codeforces Round #402 (Div. 2)_i++Codeforces Round #402 (Div. 2)_c++_02
#include<bits/stdc++.h>
using namespace std;
char s[20];
int k;
int main()
{
    scanf("%s %d",s,&k);
    int len=strlen(s);
    int ans=0,cnt=0;
    for(int i=len-1;i>=0;i--)
    {
        if(s[i]=='0') cnt++;
        if(cnt==k) break;
        if(s[i]!='0') ans++;
    }
    if(cnt==k) printf("%d\n",ans);
    else printf("%d\n",len-1);
    return 0;
}
View Code

 

C - Dishonest Sellers

题目大意:有一个商店有n个商品,价格分别为p1[ i ],1天后的价格为p2[ i ],你今天必须买 k 件商品

1天后把剩下没买过的全部买掉,问你最少花费多少钱。

 

思路:简单贪心,先将差价排序,前k个必取,后面的如果价差为负就取。

Codeforces Round #402 (Div. 2)_i++Codeforces Round #402 (Div. 2)_c++_02
#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+5;
struct node
{
    int c,id;
    bool operator < (const node &t)const
    {
        return c<t.c;
    }
}w[N];
int a[N],b[N],n,k;
bool vis[N];
int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    for(int i=0;i<n;i++) scanf("%d",&b[i]);
    for(int i=0;i<n;i++) w[i].c=a[i]-b[i],w[i].id=i;
    sort(w,w+n);
    int ans=0;
    for(int i=0;i<n;i++)
    {
        if(i<k || w[i].c<0) ans+=a[w[i].id],vis[w[i].id]=1;
    }
    for(int i=0;i<n;i++)
    {
        if(!vis[i]) ans+=b[i];
    }
    cout<<ans<<endl;
    return 0;
}
View Code

 

D - String Game

题目大意:给你两个字符串 t 和 p 且 | t | > | p |,现在我们要按给定的顺序一个一个地拿掉 t 中的字符,

问你最大拿掉几个字符,p 还是 t 的子序列。 

 

我模拟contest的时候一直看错题意,以为这个子序列的意思是,必须连在一起。还有就是我把这个题

想的太麻烦了,我刚开始想的时候如果将 t 的字符一个一个拿掉很难判断目前为止到底是不是最大值,

所以我就想从后往前一个一个按顺序插入,第一次碰到满足的情况就是答案了,然后还傻逼一样地写

了一个链表。。。。。。。。。。。我他妈我都服了我自己了,连二分搜索都不会了。。。。。。。

 

思路:直接二分最大值,可以O( n )地判断当前的 t 序列的子序列中有没有 p ,我们可以用一个w[ i ]

数组表示,第 i 个数是第几个被拿掉的。

 

Codeforces Round #402 (Div. 2)_i++Codeforces Round #402 (Div. 2)_c++_02
#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+5;
char t[N],p[N];
int a[N],w[N],n,m;
bool check(int x)
{
    int j=1;
    for(int i=1;i<=n;i++)
    {
        if(w[i]>x && t[i]==p[j]) j++;
    }
    if(j>m) return true;
    else return false;
}
int main()
{
    scanf("%s%s",t+1,p+1);
    n=strlen(t+1); m=strlen(p+1);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        w[a[i]]=i;
    }
    int l=0,r=n,ans=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))
        {
            ans=max(ans,mid);
            l=mid+1;
        }
        else r=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}
View Code

 ps : 满足某种条件的最大值最小值,优先考虑二分!!!!!!!!!!!!!