題目鏈接: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;
}