10.11T4 贪心+二分

坦克游戏3519

 

【题目描述】

Lemon最近迷上了一款坦克对战游戏。在这款游戏中,Lemon需要驾驶一辆坦克与敌军对战。坦克有很多不同的武器,每种武器有各自的特点,而Lemon所要做的就是合适地发射这些武器,对敌军造成最大的伤害。具体来说,每个武器都有两个参数:攻击力D和攻击半径R。为了简化题意,我们保证所有武器的攻击力D均不相同,所有武器的攻击半径R也均不相同。Lemon决定对这些武器的性能进行评价。当然,评价不能只看攻击力D,也不能只看攻击半径R。Lemon觉得一件武器A优于另一件武器B,当且仅当A的攻击力大于B的攻击力且A的攻击半径大于B的攻击半径。

 

接下来,Lemon想要对武器进行分组,Lemon按照以下方式分组:

首先,我们定义f(A,S)为真当且仅当在武器集合S中的任何武器都不比武器A性能更优秀。

1.令i=0

2.令i=i+1 令S=还没被分组的武器集合

3.对于每一件S中的武器A,如果f(A,S)为真,则将武器A标记为第i组(注意S在这个过程中始终保持不变)

4.如果所有武器均被分组则结束,否则转2

 

给定N个武器的D和R,你的任务是按照Lemon的规则对这些武器进行分组。

 

【输入格式】

输入文件第一行包含一个正整数N,表示武器的个数。

接下来N行,每行两个正整数D,R,描述一件武器的攻击力和攻击半径。保证所有的D两两不同,所有的R两两不同。

 

【输出格式】

输出文件包含N行,每行一个正整数,第i行的数表示第i件武器被分在了哪一组。

 

【输入样例】

5

1 4

2 2

3 3

4 1

5 5

 

【输出样例】

2

3

2

2

1

 

【样例解释】

首先我们发现武器5比武器1性能更优,所以武器1不在第1组。同理武器2、3、4也不在第1组。但没有武器比武器5性能更优,因此武器5在第1组。

接下来还剩武器1、2、3、4没被分组。我们发现这些武器中没有武器比武器1更优,于是武器1在第2组,同理武器3、4也在第2组。

接下来只剩武器2了,武器2在第3组。

此时所有武器均被分组,过程结束。

 

【数据规模约定】

时间限制为1s

对于20%的数据,N<=100.

对于40%的数据,N<=3000.

对于100%的数据,N<=100000,1<=R,D<=10^9.

 

 

 

 

 

官方题解;

此题20%数据的做法显然,直接照着题目要求模拟即可,O(N^3)
此题40%数据做法也比较简单,有两个做法:
1.对20%的做法进行改进,预先对所有的武器按D值排序,这样查找有没有更优的武器时直接查找D值比它大的就行了,时间复杂度可以证明被均摊到了O(N^2)。
2.依然预先对所有武器按D值从小到大排序,然后每次扫一遍,用一个单调栈维护即可,只要遇到R值比栈顶大就弹栈,否则入栈。扫一次就能得出一组,也是O(N^2)的。
此题满分做法是对上一个做法的改进。


仔细观察题目的流程,我们可以发现一个更优的做法。
首先我们发现同一组内的武器,按D值从大到小排序后,R值必然也是从小到大的。
而且我们发现,如果一件武器A的D值比另一件武器B的D值大,那么武器B不会影响到武器A的分组。
于是考虑把武器按D值从大到小排序,然后逐个加入武器,并为新加入的武器找到合适的组。因为在新加入一件武器之前,我们已经加入了所有D值更大的武器,而剩下的武器都不会影响当前武器的分组,所以现在得出的组号就是最终的组号。
假设D值最大的前x个武器已经全部加入组,而且现在已经有k组了,   定义第i组里最大的R值为maxR(i),那么我们发现maxR(i)必然随i递减。
我们考虑加入第x+1个武器,我们发现,按照题目要求,这件武器必然会加入到第i组,i是最小的让maxR(i)<D成立的i值。
于是我们直接用数组存储所有组的maxR,新加入武器时二分查找到加入位置,然后更新对应的那个maxR即可。
时间复杂度O(NlgN)

 

 

 

 

本人感想:

首先我一开始还是想到了先对某一维进行排序,然后再次对另一维进行操作,但是我发现很难维护R值,有一点逆序对的感觉

看了题解之后我认为这种题目还是需要先进行手动的模拟,然后才能说找到了规律(但是先排序后思考必须是基本操作)

发现如果不是偏序就一定会在一个组里面,然后我们就会发现如果是偏序就一定不在一个区间,这就是我们探究不同组的条件

然后我们再来看顺序问题,题目中很显然是先把综合能力高的先给排进去,说明D,R都是最大的

我们维护了D,所以之后我们维护R就可以了,后面不会影响前面的决策理解如下:

D肯定比前面小,所以如果R比前面大就直接放到前面去

R比前面小自然就要新开一组

一般这种题我们维护了一维之后我们要对另一维要么进行区间操作,要么进行最值操作,总之我们维护R的时候应该抛弃D,二分

code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define N 1000006
 5 using namespace std;
 6 struct node{
 7     int d,r,id,gr;
 8 }e[N];
 9 bool cmp(const node&a,const node &b){
10     return a.d>b.d;
11 }
12 bool bmp(const node&a,const node&b){
13     return a.id<b.id;
14 }
15 int R[100006],now;
16 int main(){
17     int n;
18     cin>>n;
19     for(int i=1;i<=n;i++){
20         cin>>e[i].d>>e[i].r;
21         e[i].id=i;
22     }
23     sort(e+1,e+n+1,cmp);
24 //    for(int i=1;i<=n;i++){
25 //        cout<<"l->"<<e[i].d<<" r->"<<e[i].r<<'\n';
26 //    } 
27     for(int i=1;i<=n;i++){
28         if(!now){//如果一开始是空的那么就要加进去 
29             R[++now]=e[i].r;
30             e[i].gr=now;
31             continue;
32         }
33         if(e[i].r<=R[now]){//如果比最小的都要小 
34             R[++now]=e[i].r;//新开一组 
35             e[i].gr=now;//归属确定 
36             continue;
37         }
38         int l=1,r=now,ans;
39         while(l<=r){
40             int mid=l+r>>1;
41             if(R[mid]>=e[i].r)l=mid+1;
42             else r=mid-1,ans=mid;
43         }
44         R[ans]=e[i].r;
45         e[i].gr=ans;
46 //        R[pos]=e[i].r;
47 //        e[i].gr=pos;
48     }
49     sort(e+1,e+n+1,bmp);
50     for(int i=1;i<=n;i++)cout<<e[i].gr<<'\n';
51     return 0;
52 } 

over

posted @ 2018-10-11 21:00  saionjisekai  阅读(71)  评论(0编辑  收藏  举报