本以为自己的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的更多相关文章

  1. HAOI2008 木棍分割 数据结构优化dp+二分答案

    很久之前打的题,现在补篇博客 打滚动数组 #E. 木棍分割 Accepted 100 1712 ms 1512 KiB   2019-05-07 17:01:23 Short 不打滚动数组 #419. ...

  2. HDU 4990 Ordered Subsequence --数据结构优化DP

    题意:给一串数字,问长度为m的严格上升子序列有多少个 解法:首先可以离散化为10000以内,再进行dp,令dp[i][j]为以第i个元素结尾的长度为j的上升子序列的个数, 则有dp[i][j] = S ...

  3. 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 ...

  4. Alternating Strings Gym - 100712D 简单dp && Alternating Strings II Gym - 100712L 数据结构优化dp

    比赛链接:https://vjudge.net/contest/405905#problem/D 题意: 给你一个长度为n的由0或1构成的串s,你需要切割这个串,要求切割之后的每一个子串长度要小于等于 ...

  5. $Poj2376\ Poj3171\ Luogu4644\ Cleaning\ Shifts$ 数据结构优化$DP$

    $Poj$    $AcWing$    $Luogu$ $ps:$洛谷题目与$Poj$略有不同,以下$Description$是$Poj$版.题目的不同之处在于洛谷中雇用奶牛的费用不相同,所以不可以 ...

  6. $HDOJ5542\ The\ Battle\ of\ Chibi$ 数据结构优化$DP$

    $AcWing$ $Description$ $Sol$ 首先显然是是以严格递增子序列的长度为阶段,由于要单调递增,所以还要记录最后一位的数值 $F[i][j]$表示前$i$个数中以$A_i$结尾的长 ...

  7. 0x58 数据结构优化DP

    补写一下 poj3171 设f[i]表示覆盖L~i的最小花费,把区间按左端点排序,枚举区间,f[a[i].r]=min{f[a[i].l~(a[top].r-1)]}+a[i].c (当然还要和原值比 ...

  8. 洛谷P4644 [USACO2005 Dec]Cleaning Shifts 清理牛棚 [DP,数据结构优化]

    题目传送门 清理牛棚 题目描述 Farmer John's cows, pampered since birth, have reached new heights of fastidiousness ...

  9. bzoj1233 单调队列优化dp

    https://www.lydsy.com/JudgeOnline/problem.php?id=1233 数据结构优化dp的代码总是那么抽象 题意:奶牛们讨厌黑暗. 为了调整牛棚顶的电灯的亮度,Be ...

随机推荐

  1. spring cloud 微服务调用--ribbon和feign调用

    这里介绍ribbon和feign调用两种通信服务调用方式,同时介绍如何引入第三方服务调用.案例包括了ribbon负载均衡和hystrix熔断--服务降级的处理,以及feign声明式服务调用.例子包括s ...

  2. hiho 1097 最小生成树一·Prim算法 (最小生成树)

    题目: 时间限制:10000ms 单点时限:1000ms 内存限制:256MB   描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问 ...

  3. Lua中的协同程序

    [前言] 协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.从概念上讲,线程与协同程序的主要区别在于,一个具有多个线程的 ...

  4. 【原创】大数据基础之Mesos+Marathon+Docker部署nginx

    一 安装 安装docker:https://www.cnblogs.com/barneywill/p/10343091.html安装mesos:https://www.cnblogs.com/barn ...

  5. vue 动态变量值不变化

    caseData = { lists:[] }; vm = new Vue({ el: '.hs-mt', data: caseData }); function getlist(pid,id){ $ ...

  6. Haystack-全文搜索框架

    Haystack 1.什么是Haystack Haystack是django的开源全文搜索框架(全文检索不同于特定字段的模糊查询,使用全文检索的效率更高 ),该框架支持Solr,Elasticsear ...

  7. VUE项目的目录关系

    1.页面中只有一个index.html. 2.一个js文件.在路由中. 3.主要的app.vue. 4.最后就是可以放多个vue文件的~~(一个页面对应一个vue文件,一个vue组件对应一个js中的i ...

  8. Okhttp同步请求源码分析

    进阶android,OKhttp源码分析——同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...

  9. jsp 安全

    一.  身份验证和授权 认证是检验某人真正是他/她自称的那个人的过 程.在一个Servlet/JSP应用程序中,身份验证一般通过 检查用户名密码是否正确.授权是检查该级别的用户是 否具备访问权限.它适 ...

  10. VS2010 集成标准com组件

    #include <Windows.h> #include <stdio.h> // import后,会提示找不到对应的SignCtrl.tlh文件,只需要对项目重新编译一下, ...