HDU 5596 思维题(逆向思维)*

GTW likes gt

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 416    Accepted Submission(s): 153


Problem Description
Long long ago, there were n adorkable GT. Divided into two groups, they were playing games together, forming a column. The ith GT would randomly get a value of ability bi . At the ith second, the ith GT would annihilate GTs who are in front of him, whose group differs from his, and whose value of ability is less than his.

In order to make the game more interesting, GTW, the leader of those GTs, would emit energy for m times, of which the ith time of emitting energy is ci . After the ci second, b1,b2,...,bci would all be added 1.

GTW wanted to know how many GTs would survive after the nth second.
 

Input
The first line of the input file contains an integer T(5) , which indicates the number of test cases.

For each test case, there are n+m+1 lines in the input file.

The first line of each test case contains 2 integers n and m , which indicate the number of GTs and the number of emitting energy, respectively. (1n,m50000)

In the following n lines, the ith line contains two integers ai and bi , which indicate the group of the ith GT and his value of ability, respectively. (0ai1,1bi106)

In the following m lines, the ith line contains an integer ci , which indicates the time of emitting energy for ith time.
 

Output
There should be exactly T lines in the output file.

The ith line should contain exactly an integer, which indicates the number of GTs who survive.
 

Sample Input
   
   
   
   
1 4 3 0 3 1 2 0 3 1 1 1 3 4
 

Sample Output
   
   
   
   
3
Hint
After the first seconds,$b_1=4,b_2=2,b_3=3,b_4=1$ After the second seconds,$b_1=4,b_2=2,b_3=3,b_4=1$ After the third seconds,$b_1=5,b_2=3,b_3=4,b_4=1$,and the second GT is annihilated by the third one. After the fourth seconds,$b_1=6,b_2=4,b_3=5,b_4=2$ $c_i$ is unordered.
 

Source
BestCoder Round #66 (div.2)

题意:n个GT排列在一起,他们有两组,有可能是第0组的,也有可能是第1组的。每个人都有一个能力值。每次第i秒第i个人都会对他前面的另一组的人发起攻击,如果能力值比他低,就会退出游戏。另外还有m个数字Ci,在第Ci秒末尾的时候,前Ci个存活的人的能力都会+1,问最后剩余的人数

思路:正向去暴力肯定会超时,  但倒着看的话,前面加的总和C 就相当于把后面的数减去C (因为前面加数的时刻  是在判断第i个数是否可以清除前面数 之前的)。

只需记录第i个数该减去多少就行了。然后寻找最大值进行维护更新。

逆向思维:

我们发现 b_1,b_2,...,b_x都加 11就相当于 b_{x+1},b_{x+2},...,b_n都减 11。然后我们可以倒着做,记一下最大值,如果遇到了修改操作,就把最大值减 11,然后判断一下这个人会不会被消灭掉,然后再更新一下最大值。

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int id,val;
}p[100000];
int b[100000];
int st[100000];
int main()       //逆向思维,倒着判断最大值是否比前面的要大,是同族就更新,不是就num--;
{                //此处的最大值是原值减去前面的值要长的值数(前面的加1 就等价后面的数减1 )
    int T,n,m;
    while(~scanf("%d",&T))
    {
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d",&p[i].id,&p[i].val);
            }
            memset(b,0,sizeof(b));
            for(int i=0;i<m;i++)
            {
                int t;
                scanf("%d",&t);
                t++;            //t秒之后
                b[t]++;         //后面要减少的值
            }
            st[0]=0;
            for(int i=1;i<=n;i++)
            {
                st[i]=st[i-1]+b[i];  //第i个值要减少的值
            }
            //for(int )
            int Max1=-1,Max2=-1,num=n;
            for(int i=n;i>=1;i--)
            {
                int tt=p[i].val-st[i];
                if(p[i].id==0)
                {
                    if(Max2>tt)
                        num--;
                    if(Max1<tt)
                        Max1=tt;
                }
                else
                {
                    if(Max1>tt)
                        num--;
                    if(Max2<tt)
                        Max2=tt;
                }
            }
            printf("%d\n",num);
        }
    }
    return 0;
}
1
3 3
1 1
0 1
1 1
3
3
3
输出
3 


 nlog(n)
#include<bits/stdc++.h>
using namespace std;
int a[100000],b[100000];
int v[100000];
int main()
{
    int T;
    while(~scanf("%d",&T))
    {
        while(T--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d",&a[i],&b[i]);
            }
            memset(v,0,sizeof(v));
            for(int i=0;i<m;i++)
            {
                int t;
                scanf("%d",&t);t++;
                v[t]++;
            }
            multiset<int>x,y;
            multiset<int>::iterator it;
            int del=0;
            for(int i=1;i<=n;i++)
            {
                del+=v[i];
                b[i]-=del;
                if(a[i])
                {
                    x.insert(b[i]);
                    it=y.upper_bound(b[i]);   //会把相同的也给删了
                    y.erase(y.begin(),it);
                }
                else
                {   y.insert(b[i]);
                    it=x.upper_bound(b[i]);
                    x.erase(x.begin(),it);
                }
            }

            printf("%d\n",x.size()+y.size());
        }
    }
    return 0;
}
1
3 3
1 1
0 1
1 1
3
3
3
输出
1 


你可能感兴趣的:(HDU 5596 思维题(逆向思维)*)