数据结构优化dp
本以为自己的dp已经成熟了没想到在优化上面还是欠佳 或者是思路方面优化dp还不太行。
赤壁之战 当然 很有意思的题目描述 大体上是苦肉计吧 。盖黄 ...
题意是 求出长度为m的严格上升子序列的个数 这个还比较基础。阶段比较明显。
f[i][j] 表示前i个数字当中选出了j个数字的方案数 显然的状态转移是 f[i][j]+=f[k][j-1](a[k]<a[i]&&1<=k<i)
枚举状态 n^2 枚举决策 k O(n) 总复杂度 n^3 这样看起来是过不了这道题的。
考虑如∑快速寻找决策注意我们只要值不要k这个下标所以 线段树 树状数组搞一搞即可。
复杂度 n^2logn (注意将a[i]进行离散)没了。(注意循环顺序)
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 2147483646
#define ll long long
#define max(x,y) (x>y?x:y)
#define min(x,y) (x>y?y:x)
#define mod 1000000007
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?putchar('-'),x=-x:;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=;
int n,m,T,top,ans;
int a[MAXN],b[MAXN],c[MAXN];
int f[MAXN][MAXN];//f[i][j] 表示前i个数字当中选出j个数字的方案数
//f[i][j]+=f[k][j-1](a[k]<a[i])
void discrete()
{
top=;
sort(a+,a++n);
for(int i=;i<=n;++i)if(i==||a[i]!=a[i-])a[++top]=a[i];
for(int i=;i<=n;++i)b[i]=lower_bound(a+,a++top,b[i])-a;
}
void add(int x,int y)
{
for(;x<=top;x+=x&(-x))c[x]=(c[x]+y)%mod;
return;
}
int ask(int x)
{
int cnt=;
for(;x;x-=x&(-x))cnt=(cnt+c[x])%mod;
return cnt%mod;
}
int main()
{
//freopen("1.in","r",stdin);
T=read();
for(int w=;w<=T;++w)
{
memset(f,,sizeof(f));
n=read();m=read();ans=;
for(int i=;i<=n;++i)b[i]=a[i]=read(),f[i][]=;
discrete();
for(int j=;j<=m;++j)
{
memset(c,,sizeof(c));
for(int i=;i<=n;++i)
{
int xx=ask(b[i]-);
f[i][j]=(f[i][j]+xx)%mod;
add(b[i],f[i][j-]);
}
}
for(int i=m;i<=n;++i)ans=(ans+f[i][m])%mod;
printf("Case #%d: %d\n",w,ans);
}
return ;
}
算是很水的一道题目。
这道题是一个 什么东西 我首先想到一个O(n)的dp
f[i][0/1]表示到达第i个栅栏在其左端或者在其右端已经经过的最小距离。
显然 f[i][0]=min(f[i][0],min(f[i-1][1]+|y[i-1]-x[i]|,f[i-1][0]+|x[i]-x[i-1|);
或 f[i][1]=min(f[i][1],min(f[i-1][1]+|y[i-1]-y[i]|,f[i-1][0]+|y[i]-x[i-1|);
仔细观察貌似不太对 因为对于其他决策 1=<j<i 来说也是可以转移到i 的所以貌似这个不太对。
我继续想 有了 f[i][j] 表示到达第i个栅栏的第j个位置的最小价值
转移 f[i][j]=min(f[i][j],f[i-1][k]+|j-k|); 这个好,明显转移时正确的 因为是最优子结构嘛。
当然也显然 这个dp转移不太友好就算我将其坐标进行离散化 复杂度也是n^3的
显然 n^2的都不太能过别说n^3的了,我可以优化:
拆开绝对值 f[i][j]=min(f[i][j],f[i-1][k]+j-k);(k<=j) f[i][j]=min(f[i][j],f[i-1][k]+k-j) k>j
j为已知 不管 f[i-1][k]-k显然是具有单调性的单调队列优化寻找决策 里面存着最小的k这个决策即可。
对于k>j同理 神奇的发现这 优化到了n^2 非常有意思。
我好想能拿到绝大多数分了 但是这依然是在超时的边缘的。不管了我已经尽力了。
正解是这样的 对于第二个dp 这个状态是不优的 因为这样做毫无价值好吧。。。
存那么多点的状态其实没必要我们只需存对于某个栅栏的两个端点即可。
经过贪心我们可以发现 对于第一个dp 我们的状态转移时这样的 :
f[i][0]=min(f[k][0]+abs(x[i]-x[k]),f[k][1]+abs(w[k]-x[i]));
f[i][1]=min(f[k][0]+abs(x[k]-w[i]),f[k][1]+abs(w[k]-w[i]));
其中 1<=k<i (还有一些限制没写看起来状态转移是错的)
对于当前i这个栅栏我们要走到其两端那么我只用看是否有一个决策前面已经覆盖了这个端点如果覆盖了这个端点那么这个决策之前的所有决策都是不合法的 因为他们不能直接以直线的形式过来这有当前决策可以以直线过来,因为没有其他的栅栏挡住了它。
我们完全可以开个数组来模拟这个过程 仔细思考贪心是正确的。且不具后效性。
但是这有转移仍是n^2 考虑优化 对于线段覆盖区间这种问题应该是有一种做法叫做浮水法能以很快的时间做出。
类似于 HAoi某一年的贴海报 当然这道题我是直接线段树的。
那么这个区间覆盖直接线段树即可。值得一提的是有坑点。
起点和输入和终点是否连到一块需注意这个坑了我好久。
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 2147483646
#define ll long long
#define l(x) t[x].l
#define r(x) t[x].r
#define add(x) t[x].add
#define k(x) t[x].k
#define z p<<1
#define y p<<1|1
#define max(x,y) (x>y?x:y)
#define min(x,y) (x>y?y:x)
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(ll x)
{
x<?putchar('-'),x=-x:;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=,maxn=;
int n,m;
int x[MAXN],w[MAXN];
ll f[MAXN][];//f[i][0/1]表示到达第i个栅栏的左边或者右边值最优
struct wy
{
int l,r;
int k;//决策
int add;
}t[(maxn<<)+];
void build(int p,int l,int r)
{
l(p)=l;r(p)=r;
if(l==r)return;
int mid=(l+r)>>;
build(z,l,mid);
build(y,mid+,r);
return;
}
void pushdown(int p)
{
add(y)=add(z)=add(p);
k(y)=k(z)=add(p);
add(p)=;return;
}
void change(int p,int l,int r,int v)
{
if(l<=l(p)&&r>=r(p))
{
add(p)=v;
k(p)=v;
return;
}
if(add(p))pushdown(p);
int mid=(l(p)+r(p))>>;
if(l<=mid)change(z,l,r,v);
if(r>mid)change(y,l,r,v);
return;
}
int ask(int p,int e)
{
if(l(p)==r(p))return k(p);
int mid=(l(p)+r(p))>>;
if(add(p))pushdown(p);
if(e<=mid)return ask(z,e);
else return ask(y,e);
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
memset(f,,sizeof(f));
for(int i=;i<=n;++i)
{
x[i]=read()+maxn;
w[i]=read()+maxn;
}
build(,,maxn<<);
f[][]=f[][]=;
x[]=maxn;w[]=maxn;
for(int i=;i<=n;++i)
{
int k1=ask(,x[i]);
int k2=ask(,w[i]);
f[i][]=min(f[k1][]+abs(x[i]-x[k1]),f[k1][]+abs(w[k1]-x[i]));
f[i][]=min(f[k2][]+abs(x[k2]-w[i]),f[k2][]+abs(w[k2]-w[i]));
change(,x[i],w[i],i);
}
put(min(f[n][]+abs(w[n]-m-maxn),f[n][]+abs(x[n]-m-maxn)));
return ;
}
dp很有意思
数据结构优化dp的更多相关文章
- HAOI2008 木棍分割 数据结构优化dp+二分答案
很久之前打的题,现在补篇博客 打滚动数组 #E. 木棍分割 Accepted 100 1712 ms 1512 KiB 2019-05-07 17:01:23 Short 不打滚动数组 #419. ...
- HDU 4990 Ordered Subsequence --数据结构优化DP
题意:给一串数字,问长度为m的严格上升子序列有多少个 解法:首先可以离散化为10000以内,再进行dp,令dp[i][j]为以第i个元素结尾的长度为j的上升子序列的个数, 则有dp[i][j] = S ...
- The Battle of Chibi(数据结构优化dp,树状数组)
The Battle of Chibi Cao Cao made up a big army and was going to invade the whole South China. Yu Zho ...
- Alternating Strings Gym - 100712D 简单dp && Alternating Strings II Gym - 100712L 数据结构优化dp
比赛链接:https://vjudge.net/contest/405905#problem/D 题意: 给你一个长度为n的由0或1构成的串s,你需要切割这个串,要求切割之后的每一个子串长度要小于等于 ...
- $Poj2376\ Poj3171\ Luogu4644\ Cleaning\ Shifts$ 数据结构优化$DP$
$Poj$ $AcWing$ $Luogu$ $ps:$洛谷题目与$Poj$略有不同,以下$Description$是$Poj$版.题目的不同之处在于洛谷中雇用奶牛的费用不相同,所以不可以 ...
- $HDOJ5542\ The\ Battle\ of\ Chibi$ 数据结构优化$DP$
$AcWing$ $Description$ $Sol$ 首先显然是是以严格递增子序列的长度为阶段,由于要单调递增,所以还要记录最后一位的数值 $F[i][j]$表示前$i$个数中以$A_i$结尾的长 ...
- 0x58 数据结构优化DP
补写一下 poj3171 设f[i]表示覆盖L~i的最小花费,把区间按左端点排序,枚举区间,f[a[i].r]=min{f[a[i].l~(a[top].r-1)]}+a[i].c (当然还要和原值比 ...
- 洛谷P4644 [USACO2005 Dec]Cleaning Shifts 清理牛棚 [DP,数据结构优化]
题目传送门 清理牛棚 题目描述 Farmer John's cows, pampered since birth, have reached new heights of fastidiousness ...
- bzoj1233 单调队列优化dp
https://www.lydsy.com/JudgeOnline/problem.php?id=1233 数据结构优化dp的代码总是那么抽象 题意:奶牛们讨厌黑暗. 为了调整牛棚顶的电灯的亮度,Be ...
随机推荐
- VOC2012数据集注解
VOC2012官网介绍:http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html 分割部分:参考博客:https://blog.csdn.ne ...
- 在CentOs7上部署Gunicorn
Gunicorn 的作用与优点这里就不再赘述,如不知道你也不会找这些对吧? 正文 安装简单,直接使用pip即可 pip3 install gunicorn 昨日在 Centos 中想部署Gunicor ...
- noj算法 踩气球 回溯法
描述: 六一儿童节,小朋友们做踩气球游戏,气球的编号是1-100,两位小朋友各踩了一些气球,要求他们报出自己所踩气球的编号的乘积.现在需要你编一个程序来判断他们的胜负,判断的规则是这样的:如果两人都说 ...
- 九.LNMP网站架构实践部署
期中集群架构-第九章-期中架构LNMP章节====================================================================== 01. LNMP ...
- niagara Workbench module import IntelliJ
1. 在整个网络布线中使用一种布线方式,但是两端都有RJ-45 plug 的网络连线,无论是采用方式A还是方式B 端接的方式都是试用的.网络都是通用的,双绞线的顺序与RJ-45偶的引脚序号一一对应, ...
- CSS之三个模型 盒子模型 轮廓模型 内外边距
盒子模型 最终元素的总宽度计算公式是这样的: 总元素的宽度=宽度+左填充+右填充+左边框+右边框+左边距+右边距 元素的总高度最终计算公式是这样的: 总元素的高度=高度+顶部填充+底部填充+上边框+下 ...
- ansible的logging模块用来写日志
[root@node-1 library]# cat dolog.py #!/bin/env python ANSIBLE_METADATA = { 'metadata_version': 'alph ...
- docker 搭建以太坊私有链搭建
最近区块链,火得不行,身边也有朋友准备玩这个,说是搭了一个星期,没有把环境搭建起来,叫我帮忙看看环境怎么搭建 于是我找到了官方的地址 https://github.com/ethereum/go-et ...
- matplotlib坐标轴设置-【老鱼学matplotlib】
我们可以对坐标轴进行设置,设置坐标轴的范围,设置坐标轴上的文字描述等. 基本用法 例如: import numpy as np import pandas as pd import matplotli ...
- P1265 公路修建 最小生成树
题目描述 某国有n个城市,它们互相之间没有公路相通,因此交通十分不便.为解决这一“行路难”的问题,政府决定修建公路.修建公路的任务由各城市共同完成. 修建工程分若干轮完成.在每一轮中,每个城市选择一个 ...