【Luogu】P2254瑰丽华尔兹(堆优化DP)

  题目链接

  我也不知道为什么脑子一抽就想了个堆优化……然后贼慢……

  因为上午听不懂wys的电音专场(快速傅立叶变换),然后就做了这么一道题。

  首先朴素DP很sb都能秒出。就是枚举时刻、位置(两维)然后转移。

  观察发现这是O(TNM)的,可以通过50%的数据。

  然后……(喂题目提示得太明显了吧)发现时间段只有200个,跟50%的T是一样的

  这简直就是明说:“快往O(KNM)上想!”

  然后我就不知道为啥想了个O(KNMlogn),qwq。

  枚举时刻改为枚举时间段,每个时间段枚举位置用堆优化(其实应该用单调队列)转移得出答案。

  虽然题目水+我的方法慢+我是sb+实现方法诡异+调了很久,1A还是很高兴的。

  (实现方法智障……可以当成锻炼代码能力嘛qwq)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cctype>
#define maxn 205
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Node{
    int dat,pos;
    bool operator <(const Node a)const{
        return dat>a.dat;
    }
    bool operator <=(const Node a)const{
        return dat>=a.dat;
    }
};

struct Heap{
    Node heap[505];int size;
    Heap(){ size=0;}
    inline void push(Node x){
        heap[++size]=x;
        register int i=size,k;
        while(i>1){
            k=i>>1;
            if(heap[k]<=heap[i])    return;
            swap(heap[i],heap[k]);
            i=k;
        }
        return;
    }
    inline bool empty(){    return !size;    }
    inline Node top(){    return heap[1];    }
    inline void clear(){size=0;}
    inline void pop(){
        heap[1]=heap[size--];
        register int i=1,k;
        while((i<<1)<=size){
            k=i<<1;
            if(k<size&&heap[k|1]<heap[k])    k|=1;
            if(heap[i]<=heap[k])    return;
            swap(heap[i],heap[k]);
            i=k;
        }
    }
};

Heap s[maxn];

int last,now=1;
int f[maxn][maxn][2];
char mp[maxn][maxn];

struct Line{
    int from,to,dir;
    bool operator <(const Line a)const{    return from<a.from;    }
}q[maxn];

int main(){
    int n=read(),m=read(),sx=read(),sy=read(),e=read();
    for(int i=1;i<=n;++i)    scanf("%s",mp[i]+1);
    for(int i=1;i<=e;++i)    q[i]=(Line){read(),read(),read()};
    sort(q+1,q+e+1);
    memset(f,-127/3,sizeof(f));
    f[sx][sy][last]=0;
    for(int i=1;i<=e;++i){
        int from=q[i].from,to=q[i].to,dir=q[i].dir;
        if(dir<3)
            for(int j=1;j<=m;++j){
                s[j].clear();
                if(dir==1){
                    int cnt=0;
                    for(int k=n;k;--k){
                        f[k][j][now]=-100000000;
                        cnt++;
                        if(mp[k][j]=='x'){
                            s[j].clear();
                            continue;
                        }
                        if(s[j].empty()){
                            f[k][j][now]=f[k][j][last];
                            s[j].push((Node){f[k][j][last]-cnt,k}); 
                            continue;
                        }
                        Node ret=s[j].top();
                        while((!s[j].empty())&&ret.pos-k>to-from+1){
                            s[j].pop();
                            ret=s[j].top();
                        }
                        if(s[j].empty()){
                            f[k][j][now]=f[k][j][last];
                            s[j].push((Node){f[k][j][last]-cnt,k});
                            continue;
                        }
                        //printf("%d %d %d %d\n",k,j,ret.pos,f[ret.pos][j][last]+ret.pos-k);
                        f[k][j][now]=max(f[k][j][last],f[ret.pos][j][last]+ret.pos-k);
                        s[j].push((Node){f[k][j][last]-cnt,k});
                    }
                }
                else{
                    int cnt=0;
                    for(int k=1;k<=n;++k){
                        f[k][j][now]=-100000000;
                        cnt++;
                        if(mp[k][j]=='x'){
                            s[j].clear();
                            continue;
                        }
                        if(s[j].empty()){
                            f[k][j][now]=f[k][j][last];
                            s[j].push((Node){f[k][j][last]-cnt,k});
                            continue;
                        }
                        Node ret=s[j].top();
                        while((!s[j].empty())&&k-ret.pos>to-from+1){
                            s[j].pop();
                            ret=s[j].top();
                        }
                        if(s[j].empty()){
                            f[k][j][now]=f[k][j][last];
                            s[j].push((Node){f[k][j][last]-cnt,k});
                            continue;
                        }
                        f[k][j][now]=max(f[k][j][last],f[ret.pos][j][last]+k-ret.pos);
                        s[j].push((Node){f[k][j][last]-cnt,k});
                    }
                }
            }
        else
            for(int j=1;j<=n;++j){
                s[j].clear();
                if(dir==4){
                    int cnt=0;
                    for(int k=1;k<=m;++k){
                        f[j][k][now]=-100000000;
                        cnt++;
                        if(mp[j][k]=='x'){
                            s[j].clear();
                            continue;
                        }
                        if(s[j].empty()){
                            f[j][k][now]=f[j][k][last];
                            s[j].push((Node){f[j][k][last]-cnt,k});
                            continue;
                        }
                        Node ret=s[j].top();
                        while((!s[j].empty())&&k-ret.pos>to-from+1){
                            s[j].pop();
                            ret=s[j].top();
                        }
                        if(s[j].empty()){
                            f[j][k][now]=f[j][k][last];
                            s[j].push((Node){f[j][k][last]-cnt,k});
                            continue;
                        }
                        //printf("%d %d %d\n",j,k,f[j][ret.pos][last]+k-ret.pos);
                        f[j][k][now]=max(f[j][k][last],f[j][ret.pos][last]+k-ret.pos);
                        s[j].push((Node){f[j][k][last]-cnt,k});
                    }
                }
                else{
                    int cnt=0;
                    for(int k=m;k;--k){
                        f[j][k][now]=-100000000;
                        cnt++;
                        if(mp[j][k]=='x'){
                            s[j].clear();
                            continue;
                        }
                        if(s[j].empty()){
                            f[j][k][now]=f[j][k][last];
                            s[j].push((Node){f[j][k][last]-cnt,k});
                            continue;
                        }
                        Node ret=s[j].top();
                        while((!s[j].empty())&&ret.pos-k>to-from+1){
                            s[j].pop();
                            ret=s[j].top();
                        }
                        if(s[j].empty()){
                            f[j][k][now]=f[j][k][last];
                            s[j].push((Node){f[j][k][last]-cnt,k});
                            continue;
                        }
                        //printf("%d %d %d\n",j,k,f[j][ret.pos][last]+ret.pos-k);
                        f[j][k][now]=max(f[j][k][last],f[j][ret.pos][last]+ret.pos-k);
                        s[j].push((Node){f[j][k][last]-cnt,k});
                    }
                }
            }
        swap(now,last);
    }
    int ans=0;
    for(int i=1;i<=n;++i)    
        for(int j=1;j<=m;++j)    ans=max(ans,f[i][j][last]);
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-02-06 12:35  Konoset  阅读(189)  评论(0编辑  收藏  举报