【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;
}

原文地址:https://www.cnblogs.com/cellular-automaton/p/8421736.html

时间: 2024-10-13 10:56:31

【Luogu】P2254瑰丽华尔兹(堆优化DP)的相关文章

【BZOJ1499】[NOI2005]瑰丽华尔兹 单调队列+DP

[BZOJ1499][NOI2005]瑰丽华尔兹 Description 你跳过华尔兹吗?当音乐响起,当你随着旋律滑动舞步,是不是有一种漫步仙境的惬意?众所周知,跳华尔兹时,最重要的是有好的音乐.但是很少有几个人知道,世界上最伟大的钢琴家一生都漂泊在大海上,他的名字叫丹尼•布德曼•T.D.•柠檬•1900,朋友们都叫他1900. 1900在20世纪的第一年出生在往返于欧美的邮轮弗吉尼亚号上,很不幸他刚出生就被抛弃了,成了孤儿.1900孤独的成长在弗吉尼亚号上,从未离开过这个摇晃的世界.也许是对他

征途堆积出友情的永恒「堆优化dp」

直接写题解: 很简单的dp暴力转移式子:f[i]=MAX{f[j]+max(tax[j],sum[i]-sum[j])} 观察式子,只有一个变量sum[i]; 而其他都为定量; 则考虑维护 两个定量:f[j]+tax[j]   ||  f[j]-sum[j] 而要找耗费最小;考虑用堆维护一个量; 注意是一个量; 为什么不是两个量? 想想,你在dp式子中取的max;不是取tax[j]就是取deta(sum); 那就是说如果你使一个量主动;那么另一个量就是被动的,.由你确定的这个量决定的 所以就维护

wikioi-1748 瑰丽华尔兹 -单调队列优化DP

根据题意,很明显可以推出DP方程. 假如只考虑向左的方向: dp[t][i][j]:  第t个时间段末滑行到i,j最长滑行的距离. dp[t][i][j]=dp[t-1][i][1..k]+(j-k)=dp[t-1][i][1..k]-k+j(k<=j)很明显,可以使用单调队列优化. 最终时间复杂度为O(n*m*k) #include<stdio.h> #include<string.h> #include<algorithm> #include<iostr

bzoj1499[NOI2005]瑰丽华尔兹 单调队列优化dp

1499: [NOI2005]瑰丽华尔兹 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1802  Solved: 1097[Submit][Status][Discuss] Description 你跳过华尔兹吗?当音乐响起,当你随着旋律滑动舞步,是不是有一种漫步仙境的惬意?众所周知,跳华尔兹时,最重要的是有好的音乐.但是很少有几个人知道,世界上最伟大的钢琴家一生都漂泊在大海上,他的名字叫丹尼•布德曼•T.D.•柠檬•1900,朋友们都叫他1900

【DP】【单调队列】【NOI2005】瑰丽华尔兹

340. [NOI2005] 瑰丽华尔兹 ★★★ 输入文件:adv1900.in 输出文件:adv1900.out 简单对比 时间限制:1 s 内存限制:128 MB [任务描述] 你跳过华尔兹吗?当音乐响起,当你随着旋律滑动舞步,是不是有一种漫步仙境的惬意?众所周知,跳华尔兹时,最重要的是有好的音乐.但是很少有几个人知道,世界上最伟大的钢琴家一生都漂泊在大海上,他的名字叫丹尼?布德曼?T.D.?柠檬?1900,朋友们都叫他1900. 1900出生于20世纪的第一年出生在往返于欧美的邮轮弗吉尼亚

【bzoj1097】[POI2007]旅游景点atr 状压dp+堆优化Dijkstra

题目描述 FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之后立刻去下一个城市登山,而是希望去另外什么地方喝下午茶.幸运的是,FGD的旅程不是既定的,他可以在某些旅行方案之间进行选择.由于FGD非常讨厌乘车的颠簸,他希望在满足他的要求的情况下,旅行的距离尽量短,这样他就有足够的精力来欣赏风景或者是泡MM了^_^.整个城市交通网络包含N个城市以及城市与城市之间的双向道路M条

HDU 4284 状压dp+spfa堆优化

题意: 给定n个点 m条无向边 d元. 下面m行表示每条边 u<=>v 以及花费 w 下面top 下面top行 num c d 表示点标为num的城市 工资为c 健康证价格为d 目标是经过给定的top个城市,当到达该城市时,必须马上购买该城市的健康证并打工赚钱(每个城市只打工1次) 问从1城市出发,最后回到1城市,能否收集到所有的健康证 思路: 由于top很小,所以状压dp dp[i][tmp]表示当前处于i点 经过城市的状态为tmp时 身上最多的钱. 首先对dis数组floyd 跑出最短路,

bzoj1233: [Usaco2009Open]干草堆tower 单调队列优化dp

又是一道单调队列优化dp的题目 这道题呢 先要了解一个结论,在多种可行的堆叠方案中,至少有一种能使层数最高的方案同时使得底边最短.即底边最短的,层数一定最高. 这个是zkw大神得出的 我也不会证明来着 反正这样之后我们就可以得出正确的方法了 递推式 F[i]=min(sum[j-1]-sum[i-1])  j>i 且 sum[j-1]-sum[i-1]>=F[j] 易得在满足的条件下j当然是越小越好了嘛 而这样得出的方程又满足一定的单调性 这样调整之后队首就是我们要的答案啦 又对于转移条件 f

【Luogu】P3628特别行动队(斜率优化DP)

题目链接 设c[i]是战斗力前缀和,f[i]是考虑前i个,且最后一组分到第i个士兵为止的战斗力之和 则有朴素状态转移方程 for(int i=1;i<=n;++i) for(int j=0;j<i;++j){ int x=c[i]-c[j]; f[i]=min(f[i],a*x*x+b*x+c); } 然后考虑优化. 假设f[i]最优结果是从f[j]转移过来,同时有一个不那么优的转移f[k] 则有$f[j]+a*squa(c[i]-c[j])+b*(c[i]-c[j])+c>f[k]+a