【二分答案】SDUT-4072 小绿的脱单梦

Problem Description

小绿一直坚持不懈的追求他的一个高中女同学。最近妹子终于被他打动,决定在接下来n天对他进行m项考验(同一项考验可能会在不同的两天重复进行,通过一次即可),如果他能全部通过,妹子就会答应和他交往。
小绿在得到消息后,兴奋不已,虽然他是一个不折不扣的weisuo死宅,虽然他除了代码什么都不会,但是他对自己的IQ十分自信!他能准确的估计自己通过某一项考验需要准备多少天,当然如果在某天去参加考验,那么那天就没时间准备其他项考验了。现在他偷偷的知道了妹子对他的考验安排,形势一片大好。小绿想尽快完成,他当然知道最少要多少天内完成所有考验,不过他决定将这个问题送给学弟,来分享他喜悦的心情。

Input

首先第一行输入一个整数T(T<=30)代表接下来有T组数据。
每组数据开头先输入两个整数n,m(0 < n, m <100000),意义如题。
第二行n个以空格隔开的非负整数 ai (0 <= ai <= m),代表第i天妹子将会对小绿进行第ai项考验(ai=0代表第i天不进行任何考验)。
第三行m个以空格隔开的非负整数 bi (1 <= bi <= 100000),代表小绿通过第i项测试之前需要准备够bi天。

Output

输出小绿完成所有的考验所需要的最短时间,如果在n天之内他不能完成所有考验请输出-1。

Example Input

3
5 1
1 1 1 1 1
5
10 3
0 0 1 2 3 0 2 0 1 2
1 1 4
5 1
0 0 0 0 1
1

Example Output

-1
9
5

#include<bits/stdc++.h>
using namespace std;
#define maxn 100055
int sum;
int a[maxn], Time[maxn], n, m;
int vis[maxn];
bool solve(int mid)
{
    //printf("mid = %d\n", mid);
    int t = mid - m, i;//t是最大可以用来准备的时间
    if(sum > t) return 0;//如果最大可以用来准备的时间,都没有最少需要的时间大的话
    memset(vis, 0, sizeof(vis));
    int num = 0;
    for(i = mid; i >= 1; i--)//从后往前暴力
    {
        if(a[i] && !vis[a[i]])
        {
            vis[a[i]] = 1;
            num++;//用来记录通过了几个考验
            t = min(t, i-1-(m-num));//更新t,此时最大可以用来准备的时间。
            t -= Time[a[i]];
            if(t < 0) break;
        }
    }
    if(t >= 0 && num == m) return 1;
    else return 0;
}
int main()
{
    int T, i;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &n, &m);
        for(i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        sum = 0;
        for(i = 1; i <= m; i++)
        {
            scanf("%d", &Time[i]);
            sum += Time[i];//完成全部考验至少需要的天数
        }
        int l = 1, r = n;
        int flag = 0;
        while(l <= r)//二分答案
        {
            int mid = (l+r)/2;
            if(solve(mid)) {//满足就缩小范围
                flag = 1;
                r = mid-1;
            }
            else l = mid+1;
        }
        if(flag) printf("%d\n", r+1);
        else printf("-1\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值