题意

https://vjudge.net/problem/CodeForces-1257D

你需要操作m个英雄去打败n只怪物,每个英雄的力量值为pi,可以打败si只怪物;每只怪物的力量值为ai。

当新的一天开始时,你可以选择其中1个英雄去打怪。若在之前已有k只怪物被打败,这个英雄将挑战第k+1只怪物,此时有两种情况:

1.英雄力量≤怪物力量,则英雄撤退,这一天结束。

2.英雄力量>怪物力量,怪物被打败。继续挑战下一只怪物。当n只怪物全部被打败,或该英雄已打败的怪物数量=si时,这一天结束。

你的任务是计算出打败所有怪物所需要的最小天数。

思路

最简单的想法就是用si大的尽可能多打。

维护每个耐力值si对应的力量最大的英雄,因为相等耐力值情况下肯定是选力量最大的要好。

再维护上面数组的后缀最大值,这个其实就是耐力值少的也可以(注意是可以!不是一定)用耐力值大的代替,比如对于耐力值i,i+1,如果i+1的力量大于i,那么完全可以用i+1代替i去打,因为耐力值比i大。

然后用双指针求解,当前遍历到第i个怪物,用j往右边延伸,看最远能打到哪个怪物,这里要实时记录这一段怪物力量的最大值,如果v[j-i+1]>=mx (v是上述处理完后缀最大值后的数组),那么就可以延伸,v[j-i+1]表示耐力值为j-i+1~n(这一段的耐力值大于mx的英雄都可以使用)的最大英雄力量值。

代码

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int N=200005;
const int mod=1e9+7;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
int a[N],v[N];
int main()
{
    std::ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            v[i]=0;
        }
        int m;
        cin>>m;
        for(int i=1;i<=m;i++)
        {
            int p,s;
            cin>>p>>s;
            v[s]=max(v[s],p);
        }
        for(int i=n-1;i>=1;i--)
        {
            v[i]=max(v[i],v[i+1]);
        }
        int i=1,j,ans=0,flag=0;
        while(i<=n)
        {
            if(a[i]>v[1])
            {
                flag=1;
                break;
            }
            j=i;
            int mx=a[i];
            while(j<=n&&v[j-i+1]>=mx)
            {
                j++;
                mx=max(mx,a[j]);
            }
            ans++;
            i=j;
 //           cout<<i<<" "<<ans<<endl;
        }
        if(flag)
            cout<<-1<<endl;
        else
            cout<<ans<<endl;
    }
    return 0;
}

  

01-06 21:00