题目链接:http://codeforces.com/contest/1257/problem/D
题目大意:有n个怪兽,对应n个攻击力,m个奥特曼(大雾),每个奥特曼有一个攻击力和攻击天数(他们可以任意派出和使用),怪兽必须按顺序打败,问最少多少个奥特曼可以击败所有怪兽,若击败不了所有怪兽,输出-1
从这篇题解中真的学到很多,写这种思维题的时候,我没有学会用整体的思维去考虑问题,应该像当初写高中数学题时候,学会从题目本身寻找突破口。
李煜东大神教我们,每道题应该分为几个子问题然后一个一个的解决。
从题解上来看,
首先,第一个子问题,非常明显,维护的重点不能放在他的攻击力上,如果对攻击力排序,而优先使用攻击力大的奥特曼,那并不能保证他的攻击天数最多,我们不能选攻击力最大的,应该选最合适的,这就是我没有想到的地方,本来我觉得可能利用攻击力高的去贪心加搜索,显然复杂度是不能够接受的。
At first, lets precalc array bst; bsti is equal to maximum hero power whose endurance is greater than or equal to i.
首先我们应该预处理出bst数组,代表的是能够攻击i天的英雄的最大攻击力是多少
维护天数很明显就可以解决我们按顺序击败怪兽的问题,天数区域内的最大值和当前bst[i]比较便可以O(n)的维护最小攻击天数,真是太精妙了。于是看懂了题解的我迫不及待的上手写代码,然而我是这么维护的
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+9;
int t,n,m;
int a[maxn];
priority_queue<int>q[maxn];
int main()
{
scanf("%d",&t);
while(t--){
for(int i=1;i<=n;i++){
while(q[i].size())q[i].pop();
}
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
scanf("%d",&m);
int ins=-1;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
for(int j=1;j<=y;j++){
q[j].push(x);
}
ins=max(ins,y);
}
int num=1,maxx=-1,ans=1,flag=1;
for(int i=1;i<=n;i++){
maxx=max(a[i],maxx);
if(maxx<=q[num].top()){
num++;
if(num>ins&&i!=n){
ans++;
num=1;
maxx=-1;
}
}
else{
if(num==1){
flag=0;
break;
}
num=1;maxx=-1;
if(q[num].top()>=a[i]){
num++;maxx=max(a[i],maxx);
ans++;
if(num>ins){
num=1;
}
}
else{
flag=0;break;
}
}
}
if(flag){
printf("%d\n\n",ans);
}
else{
printf("-1\n");
}
}
return 0;
}
我竟然不知死活的拿优先队列加n方的复杂度去维护,复杂度n2logn,哈哈。。
于是我瞟了一眼题解,就一小眼,仅仅是那么一个小眼神,我顿时就豁然开朗,仿佛见到了一个桃花源,,,,如果维护每个天数的max,然后再逆序的维护一遍max不就行了嘛!!!!真的是思维本质!能够持续打n天的最大值一定能够打n-1天呐。(这个思维是真的精妙,惊叹.jpg)
最后学到的微不足道的小玩意,少用memset清空数组,不然就会像这样
好了上代码,,,,顺便%%%全神前三百又上分了,等会补一下全神的做法
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+9;
int t,n,m;
int a[maxn];
int q[maxn];
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
q[i]=0;
}
scanf("%d",&m);
int ins=-1;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
q[y]=max(q[y],x);
ins=max(ins,y);
}
for(int i=ins-1;i>=1;i--){
q[i]=max(q[i],q[i+1]);
}
int num=1,maxx=-1,ans=1,flag=1;
for(int i=1;i<=n;i++){
maxx=max(a[i],maxx);
if(maxx<=q[num]){
num++;
if(num>ins&&i!=n){
ans++;
num=1;
maxx=-1;
}
}
else{
if(num==1){
flag=0;
break;
}
num=1;maxx=-1;
if(q[num]>=a[i]){
num++;maxx=max(a[i],maxx);
ans++;
if(num>ins){
num=1;
}
}
else{
flag=0;break;
}
}
}
if(flag){
printf("%d\n",ans);
}
else{
printf("-1\n");
}
}
return 0;
}