二分 - Exams - CodeForces - 732D

二分 - Exams - CodeForces - 732D

題意:

nmnm首行輸入包括兩個整數n和m,表示總天數爲n,有m門考試。

nd1,d2,...,dndiididi=0i第二行包括n個整數d_1,d_2,...,d_n,d_i表示第i天能夠參加第d_i門考試,若d_i=0則表示第i天無考試。

ma1,a2,...,anaiiai第三行包括m個整數a_1,a_2,...,a_n,a_i表示第i門考試需要複習準備a_i天。

m1現判斷最少需要幾天能夠考完m門課程,若不能,則輸出-1。

數據範圍:

1n,m1050dim1ai105Time limit1000msMemory limit262144kB1 ≤ n, m ≤ 10^5,0 ≤ d_i ≤ m,1 ≤ a_i ≤ 10^5\\Time \ limit:1000 ms,Memory\ limit:262144 kB

Examples

Input:
7 2
0 1 0 2 1 0 2
2 1
Output:
5

Input:
10 3
0 0 1 2 3 0 2 0 1 2
1 1 4
Output:
9

Input:
5 1
1 1 1 1 1
5
Output:
-1

分析:

kk+1若能在k天內能夠考完,則k+1天也一定能夠考完。

因此二分答案。

midr=midl=mid+1若mid天能夠考完,則r=mid,反之更新l=mid+1。

checkmid關鍵在於check函數如何判斷mid天內能否考完。

checkmidcheck函數是貪心的思想。將每一門課都儘量安排在最後考,前幾天都儘量的準備考試。若能考完說明mid可行。

cntdipre因此我們用一個cnt數組來標記最遲在哪一天能考第d_i門,pre來記錄已經準備了多少天。

cnt[k]kcnt[k]則cnt[k]表示第k門最遲必須在第cnt[k]天考完。

midcnt[di]cnt[di]=iidi先從mid天往前考慮,若cnt[d_i]還未被標記過,則更新cnt[d_i]=i,說明最遲在第i天能考第d_i門。

idi=0pre++①、若第i天能考的科目數量d_i=0,那麼這一天只能準備考試,pre++。

cnt[di]iipre++②、若cnt[d_i]≠i,說明第i天不是最遲的一天,故這一天也用來準備考試,pre++。

didia[di]a[di]<=predicheckfalsemid③、其他情況說明這一天是考第d_i門最遲的一天,而考第d_i門需要準備a[d_i]天,\\\qquad若a[d_i]<=pre,說明能把第d_i門考完。否則check函數直接返回false說明mid不可行。

mcntcnt[i]=0[1,mid]ifalse④、最後我們還要檢查一下m門考試是否都被cnt數組標記過,若有某一門未被標記過,即cnt[i]=0,\\\qquad則說明[1,mid]天當中,沒有哪一天安排了第i門考試,則返回false。

truemid⑤、否則最後返回true表示mid天內能考完全部課程。

注意: checkcnt每次check要初始化cnt數組。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

#define ll long long
#define P pair<int,int>
#define x first
#define y second
#define inf 0x3f3f3f3f

using namespace std;

const int N = 100010;

int n,m,d[N],a[N];

bool check(int x)
{
    int cnt[N];
    memset(cnt,0,sizeof cnt);
    
    for(int i=x;i;i--)
        if(!cnt[d[i]])
            cnt[d[i]]=i; 
            
    int pre=0;
    for(int i=1;i<=x;i++)
        if(!d[i]||cnt[d[i]]!=i) pre++;
        else
        {
            if(a[d[i]]>pre) return false;
            else pre-=a[d[i]];
        }
    
    for(int i=1;i<=m;i++) if(!cnt[i]) return false;
    
    return true;
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&d[i]);
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);

    int l=0,r=n+1;
    while(l<r)
    {
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }

    if(l==n+1) puts("-1");
    else cout<<l<<endl;
    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章