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;
}