数据结构优化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 ...
随机推荐
- Stack的相关API
public class Stack<E> extends Vector<E> : Stack类代表后进先出(LIFO)堆栈的对象. 它扩展了类别Vector与五个操作,允许一 ...
- Pycharm工具导入requests包(python新手)
在学习使用python的过程中选择了工具Pycharm,但是如下代码: ,起初导包一直报错,解决办法:File->Setting 点击右上角+号,打开搜素对话框 搜素需要的导包,并加入即可解决此 ...
- Python学习笔记-EXCEL操作
环境Python3 创建EXCEL,覆盖性创建 #conding=utf-8 import xlwt def BuildExcel(ExcelName,SheetName,TitleList,Data ...
- 【原创】Java基础之Session机制
Session机制 JSESSIONID是Session的标识,当客户端请求服务器端的时候,服务器端会检查是否已经给这个客户端创建过Session,也就是看客户端的请求中的header是否有Cooki ...
- Centos 7 telnet 详解
telnet命令 telnet命令用于登录远程主机,对远程主机进行管理.telnet因为采用明文传送报文,安全性不好,很多Linux服务器都不开放telnet服务,而改用更安全的ssh方式了.但仍然有 ...
- About the Mean Shift
Mean Shift算法,一般是指一个迭代的过程.即先算出当前点的偏移均值,移动该点到其偏移均值,然后以此为新的起始点,继续移动,直到满足一定的条件结束. meanshift可以被用来做目标跟踪和图像 ...
- 用 zotero 管理文献和个人知识库
这周开始用了一下 zotero. 这是一款非常好用的文献管理工具,但它更像是一个多功能的收藏夹,或者说是一个知识.笔记.文献的综合管理工具. 入门的时候搜到了阳志平老师的几个图文并茂的教程,这里也推荐 ...
- node爬取html乱码
var http = require('http'), iconv = require('iconv-lite'); http.get("http://website.com/", ...
- Django REST framework serializer 嵌套显示绝对路径
在 Django REST framework官方文档提到,当调用Serializer时,应当传入request参数,以便生成完整的url而不是相对url.使用ModelSerializer时requ ...
- 利用MySQL游标进行计算排名
SELECT a.id, a.nick_name, a.member_account, a.integral, () AS tRank #计算行号 FROM tzqc_raw_data AS a, ( ...