Educational Codeforces Round 76 (Rated for Div. 2) D - Yet Another Monster Killing Problem

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章