本以为自己的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. DCM、PLL、PMCD、MMCM相关

    摘自网上 : http://xilinx.eetop.cn/viewnews-1482 The DCM is a Digital Clock Manager - at its heart it is ...

  2. 51nod--1134 最长递增子序列 (动态规划)

    题目: 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递增的) 例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10. Input 第1行: ...

  3. 51nod--1185 威佐夫游戏 V2 (博弈, 乘法模拟)

    题目: 1185 威佐夫游戏 V2 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 有2堆石子.A B两个人轮流拿,A先拿.每次可以从一堆中取任意个或从2堆中 ...

  4. IIS无法删除应该程序池 因为它包含X个应用程序

    今天代码主分支在vs2015创建了虚拟目录http://localhost/webapp指向的物理路径是E:\webapp 之后新开了一个分支把代码放在了D:\webapp之后又在vs2015中创建了 ...

  5. Python-Django-BMS-增删改查

    无名分组 有名分组 反向解析 更改路由后不影响,动态传值 locals()传参 queryset.update() 自定义过滤器 {{forloop.counter}} new.authors.add ...

  6. python正则表达式--特殊字符

    正则表达式—特殊表达式含义 正则表达式的字母和数字表示他们自身,但多数字母和数字前加一个反斜杠时会拥有不同的含义. 下面列出了正则表达式模式语法中的特殊元素. 1.普通字符集 1)    \w     ...

  7. Reveal 使用详解

    Reveal是一款调试iOS程序UI界面的神器 官网:https://revealapp.com 下载:https://revealapp.com/download/ 建议下载至少Reveal4版本, ...

  8. Java_Character类

      Character类用于对单字符进行操作. 常用的方法: System.out.println(Character.isDigit('1')); // true 判断是否是一个数字字符 Syste ...

  9. BAT批处理中的字符串处理详解(字符串截取)

    BAT批处理中的字符串处理详解(字符串截取)   BAT批处理中的字符串处理详解(字符串截取 批处理有着具有非常强大的字符串处理能力,其功能绝不低于C语言里面的字符串函数集.批处理中可实现的字符串处理 ...

  10. python---哈希算法实现

    # coding = utf-8 class Array: def __init__(self, size=32, init=None): self._size = size self._items ...