cf1257 D - Yet Another Monster Killing Problem(二分套rmq)

D. Yet Another Monster Killing Problem
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You play a computer game. In this game, you lead a party of heroes, and you have to clear a dungeon with monsters. Each monster is characterized by its power . Each hero is characterized by his power and endurance .

The heroes clear the dungeon day by day. In the beginning of each day, you choose a hero (exactly one) who is going to enter the dungeon this day.

When the hero enters the dungeon, he is challenged by the first monster which was not defeated during the previous days (so, if the heroes have already defeated monsters, the hero fights with the monster +1). When the hero fights the monster, there are two possible outcomes:

if the monster’s power is strictly greater than the hero’s power, the hero retreats from the dungeon. The current day ends;
otherwise, the monster is defeated.
After defeating a monster, the hero either continues fighting with the next monster or leaves the dungeon. He leaves the dungeon either if he has already defeated the number of monsters equal to his endurance during this day (so, the -th hero cannot defeat more than monsters during each day), or if all monsters are defeated — otherwise, he fights with the next monster. When the hero leaves the dungeon, the current day ends.

Your goal is to defeat the last monster. What is the minimum number of days that you need to achieve your goal? Each day you have to use exactly one hero; it is possible that some heroes don’t fight the monsters at all. Each hero can be used arbitrary number of times.

Input
The first line contains one integer (1≤≤105) — the number of test cases. Then the test cases follow.

The first line of each test case contains one integer (1≤≤2⋅105) — the number of monsters in the dungeon.

The second line contains integers 1, 2, …, (1≤≤109), where is the power of the -th monster.

The third line contains one integer (1≤≤2⋅105) — the number of heroes in your party.

Then lines follow, each describing a hero. Each line contains two integers and (1≤≤109, 1≤≤) — the power and the endurance of the -th hero.

It is guaranteed that the sum of + over all test cases does not exceed 2⋅105.

Output
For each test case print one integer — the minimum number of days you have to spend to defeat all of the monsters (or −1 if it is impossible).

Example
inputCopy
2
6
2 3 11 14 1 8
2
3 2
100 1
5
3 5 100 2 3
2
30 5
90 1
outputCopy
5
-1

题意: 奥特曼打怪兽,每个奥特曼有攻击力p和体力值s。每个怪兽有攻击力t.如果p≥t,奥特曼可以打死这只怪兽。一回合派出一只奥特曼,最多打s只怪兽,遇到打不死的怪兽则回合结束。问打完所有怪兽最少多少回合。

思路: 二分套二分,再套两个rmq。先二分每回合最多打多少个怪兽,二分的值再在奥特曼中二分找到体力值够的奥特曼。得出体力值大于mid的奥特曼的最大攻击值,以及这次攻击的最大怪兽攻击值,就可以判断了。

#include 
#include 
#include 
#include 
#include 
 
using namespace std;
 
const int INF = 0x3f3f3f3f;
 
const int maxn = 2e5 + 7;
int dp[maxn][30],dp2[maxn][30],a[maxn];
int n,m;
 
struct Node
{
    int p,s;
    bool operator <(const Node &rhs)const
    {
        if(s == rhs.s)return p < rhs.p;
        return s < rhs.s;
    }
}nodes[maxn];
 
struct cmp1
{
    bool operator () (const Node &a,const Node &b) const {
        return a.s < b.s;
    }
};
 
void init1()
{
    for(int j = 1;j <= 20;j++)
    {
        for(int i = 1;i <= n;i++)
        {
            if(i + (1 << j) - 1 <= n)
            {
                dp[i][j] = max(dp[i + (1 << (j - 1))][j - 1],dp[i][j - 1]);
            }
        }
    }
}
 
void init2()
{
    for(int i = 1;i <= m;i++)dp2[i][0] = nodes[i].p;
    for(int j = 1;j <= 20;j++)
    {
        for(int i = 1;i <= m;i++)
        {
            if(i + (1 << j) - 1 <= m)
            {
                dp2[i][j] = max(dp2[i + (1 << (j - 1))][j - 1],dp2[i][j - 1]);
            }
        }
    }
}
 
int query(int x,int y)
{
    int t = log(y - x + 1) / log(2);
    return max(dp[x][t],dp[y - (1 << t) + 1][t]);
}
 
int query2(int x,int y)
{
    int t = log(y - x + 1) / log(2);
    return max(dp2[x][t],dp2[y - (1 << t) + 1][t]);
}
 
int bin(int x)
{
    int l = 1,r = m,ans = 1;
    while(r - l >= 0)
    {
        int mid = (l + r) >> 1;
        if(nodes[mid].s <= x)
        {
            ans = mid;
            l = mid + 1;
        }
        else
        {
            r = mid - 1;
        }
    }
    return ans;
}
 
bool check(int sta,int mid)
{
    int x = bin(mid + 1);
    if(nodes[x].s < mid + 1 && x < m)
        x++;
    if(nodes[x].s < mid + 1)return false;
    int y = query2(x,m);
    int ed = min(n,sta + mid);
    int mx = query(sta,ed);
    if(y >= mx)
        return true;
    return false;
}
 
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int maxx1 = 0;
        scanf("%d",&n);
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
            maxx1 = max(maxx1,a[i]);
            dp[i][0] = a[i];
        }
        init1();
 
        scanf("%d",&m);
        int maxx2 = 0;
        for(int i = 1;i <= m;i++)
        {
            scanf("%d %d",&nodes[i].p,&nodes[i].s);
            maxx2 = max(nodes[i].p,maxx2);
        }
        sort(nodes + 1,nodes + 1 + m);
 
        init2();
        if(maxx2 < maxx1)
        {
            printf("-1\n");
            continue;
        }
        int sta = 1;
        int res = 0;
        while(sta <= n)
        {
            int l = 0,r = n - sta,ans = 0,ans2 = 0;
            while(r - l >= 0)
            {
                int mid = (l + r) >> 1;
                if(check(sta,mid))
                {
                    ans2 = mid;
                    l = mid + 1;
                }
                else
                {
                    r = mid - 1;
                }
            }
            sta += ans2 + 1;
            res ++;
        }
        printf("%d\n",res);
    }
    return 0;
}

你可能感兴趣的:(#,codeforces,#,二分三分算法)