----19.7.30 今天又开了一个新专题,dp杂题,我依旧按照之前一样,这一个专题更在一起,根据个人进度选更题目;

dp就是动态规划,本人认为,动态规划的核心就是dp状态的设立以及dp转移方程的推导,这也是训练的重中之重,所以代码不那么重要,重要的就是dp的思想;

T1:

A. 消失之物

题目描述

ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN。 由于她的疏忽, 第 i 个物品丢失了。 “要使用剩下的 N - 1 物品装满容积为 x 的背包,有几种方法呢?” -- 这是经典的问题了。她把答案记为 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i, x) 表格。

这道题乍一看以为就是一个裸的背包,但是(本人太弱了)我以上来先想到的是裸的$ 0/1 $背包然后就想跑$ n $遍$  0/1 $背包,但是显然复杂度会爆炸,所以要考虑别的方法,但是还是逃不掉的dp,重点就在状态的转移,这个转移其实可以在之前的0/1背包的基础上进行转移,那么我们可以设f[maxn][2],也就是开一维半的数组,设状态为$ f[j][1] $表示背包容量为j时的方案数,因为题目恶心了我们就是要输出一个矩阵,那么我们就需要再循环i表示当我们去掉i时$  f[j][1] $就是背包容量为j时的方案数,那么就可以列出状态转移方程:(这里的0/1表示能否可以解决!)

$  f[j][0]+=f[j-v[i]] $

$  f[j][1]=f[j][0]+f[j-v[i]][1] (j-v[i]>0)$

$  f[j][1]=f[j][0]  (j-v[i]<=0) $

然后就结束了,一定要记得多多取模(他让输出最低的一位,所以不那么恶心!),这道题没什么细节,就不站代码了,评论区留给你们!

UPD:这道题skyh的打法刷新了我的dp观,我是真的震惊

天黄的这道题使用分治带dp打的,很新颖,不愧是dalao(orz),那么我也稍说一下skyh的思路:

$ (after 10 mins...) $其实和我的思路差不多,就是分治了一下,qwq

 #include<iostream>
#include<cstdio>
using namespace std;
const int N=;
int n,m,w[N];
short dp[][N];
void solve(int dep,int l,int r){
if(l==r){
for(int i=;i<=m;++i) printf("%d",dp[dep-][i]);
puts("");
return ;
}
int mid=l+r>>;
for(int i=;i<=m;++i) dp[dep][i]=dp[dep-][i];
for(int i=mid+;i<=r;++i) for(int j=m;j>=w[i];--j) (dp[dep][j]+=dp[dep][j-w[i]])%=;
solve(dep+,l,mid);
for(int i=;i<=m;++i) dp[dep][i]=dp[dep-][i];
for(int i=l;i<=mid;++i) for(int j=m;j>=w[i];--j) (dp[dep][j]+=dp[dep][j-w[i]])%=;
solve(dep+,mid+,r);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i) scanf("%d",&w[i]);
dp[][]=; solve(,,n);
return ;
}

skyh

//copyright by skyh

//copy from skyh  orz

B. 方伯伯的玉米田

内存限制:128 MiB 时间限制:6000 ms 标准输入输出
 
 

题目描述

方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美。
这排玉米一共有N株,它们的高度参差不齐。
方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列。
方伯伯可以选择一个区间,把这个区间的玉米全部拔高1单位高度,他可以进行最多K次这样的操作。拔玉米则可以随意选择一个集合的玉米拔掉。
问能最多剩多少株玉米,来构成一排美丽的玉米。

输入格式

第1行包含2个整数n,K,分别表示这排玉米的数目以及最多可进行多少次操作。
第2行包含n个整数,第i个数表示这排玉米,从左到右第i株玉米的高度ai。

输出格式

输出1个整数,最多剩下的玉米数。

这是学长讲过的一道例题,是数据结构优化dp,而且这道题需要证明一个引理;

引理:所有操作的右端点一定是n(最右侧)的那个点。

证明:如果将一个区间内的权值都加上一个数,只会出现两种情况:

  1.区间的左侧:

    之前比区间内的数小的在操作之后还是比他小;

    之前比区间内的数大的在操作之后没有他大(比他小!);

    之前比区间内的数大的在操作之后还是比他大;

  所以区间左侧不会降低ans,还可能增加ans

  2.区间的右侧:

    之前比区间内的数小在操作之后还是比他小;

    之前比区间内数大的,现在不一定比他大;

    之前比区间内数大的,现在还是比他大;

 所以区间右侧不会升高ans,还可能降低ans;

所以要保证答案最优,就要有区间右侧最小,所以就有所有的操作都以n为有区间的端点;

证明完毕;

接着回到题解,这里有了上面的引理,我们就能推出dp的状态转移方程;

设$ f[i][j] $表示以i为结尾,共被拔高了j次的ans,即以i为结尾,共被j个区间覆盖;

那么,我们根据定义可以推出状态转移方程:

  $ f[i][j]=max{f[k][l]}+1 (1<=k<=i,1<=l<=j ) $且要合法才能转移;

那么这一看如果暴力求解的话复杂度爆表,所以这个可以使用二维树状数组进行优化,然后就是$ O(n*m) $的复杂度;

代码实现也很简单:

 #include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cstdio>
using namespace std;
#define re register
int a[],c[][],n,m,maxa,ans,sum,res;
int lowbit(int x){return x&(-x);}
void change(int x,int y,int z)
{
int yy=y;
while(x<=maxa+m)
{
y=yy;
while(y<=m+)
{
c[x][y]=max(c[x][y],z);
y+=lowbit(y);
}
x+=lowbit(x);
}
}
int getsum(int x,int y)
{
int yy=y,sum=;
while(x>)
{
y=yy;
while(y>)
{
sum=max(sum,c[x][y]);
y-=lowbit(y);
}
x-=lowbit(x);
}
return sum;
}
int main()
{
//freopen("simple.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
maxa=max(maxa,a[i]);
}
for(int i=;i<=n;i++)
{
for(int j=m;j>=;j--)
{
res=getsum(a[i]+j,j+)+;
change(a[i]+j,j+,res);
ans=max(ans,res);
}
}
printf("%d\n",ans);
return ;
}

玉米田

C. 拦截导弹

内存限制:512 MiB 时间限制:1500 ms 标准输入输出
 

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。

我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。

输入格式

第一行包含一个正整数

,表示敌军导弹数量;

下面 行按顺序给出了敌军所有导弹信息:

第i+1行包含2个正整数

,分别表示第 枚导弹的高度和速度。

输出格式

输出包含两行。

第一行为一个正整数,表示最多能拦截掉的导弹数量;

第二行包含n个0到1之间的实数,第i个数字表示第i枚导弹被拦截掉的概率(你可以保留任意多位有效数字)。

样例

样例输入

4
3 30
4 40
6 60
3 30

样例输出

2
0.33333 0.33333 0.33333 1.00000

数据范围与提示

对于100%的数据,

这个spj其实是假的,并没有部分分,但是这道题确实是一道好题,其实之前做过拦截导弹的简单版,就是线性dp,所以这还是用线性dp,显然是不行的,因为我以为是spj已经WA0好几次了,因为这道题有三个限制条件,要同时满足三个限制条件,不就是cdq分治吗,然后就把统计答案的dp扔到cdq的过程中,然后,就切了。就这样切了,当然不是,反正我不是1A的,记得开double!

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=;
inline int read()
{
int x=,f=;char cc;cc=getchar();
while(cc>''||cc<''){if(cc=='-')f=-;cc=getchar();}
while(cc>=''&&cc<=''){x=(x<<)+(x<<)+(cc^);cc=getchar();}
return x;
}
struct tree
{
int f;double w;
tree(){f=,w=;}
}t[maxn];
int n;
int st[maxn],top=,th,tv;
inline int lowbit(int x){return x&(-x);}
inline void add(int p,int f,double w)
{
while(p<n)
{
if(t[p].f<f)
{
if(t[p].f==)st[++top]=p;
t[p].f=f;t[p].w=w;
}
else if(t[p].f==f)t[p].w+=w;
p+=lowbit(p);
}
return;
}
tree ask(int p)
{
tree res;
while(p)
{
if(t[p].f>res.f) res=t[p];
else if(t[p].f==res.f) res.w+=t[p].w;
p-=lowbit(p);
}
return res;
}
struct Dan
{
int h,v,f[],id,t;
double g[];
}a[maxn],q[maxn];
int wh[maxn],wv[maxn],id[maxn];
int rk[maxn];
inline bool cmp(int x,int y){return a[x].h<a[y].h||(a[x].h==a[y].h&&a[x].id<a[y].id);}
int cmpid(Dan a,Dan b){return a.id<b.id;}
int cnt=;
void cdq(int l,int r,int mode)
{
if(l==r)
{
if(a[l].f[mode]<){a[l].f[mode]=;a[l].g[mode]=;}
return;
}
int mid=(l+r)>>;
memcpy(q+l,a+l,sizeof(Dan)*(r-l+));
int q1=l,q2=mid+;
for(int i=l;i<=r;i++)
if(q[i].t<=mid)a[q1++]=q[i];
else a[q2++]=q[i];
cdq(l,mid,mode);
q1=l;
for(int i=mid+;i<=r;i++)
{
while(q1<=mid && a[q1].id<a[i].id)
add(a[q1].v,a[q1].f[mode],a[q1].g[mode]),q1++;
tree res=ask(a[i].v);
if(!res.f)continue;
if(res.f+>a[i].f[mode])
{
a[i].f[mode]=res.f+;
a[i].g[mode]=res.w;
}
else if(res.f+==a[i].f[mode]) a[i].g[mode]+=res.w;
}
while(top){t[st[top]].w=;t[st[top--]].f=;}
cdq(mid+,r,mode);
merge(a+l,a+mid+,a+mid+,a+r+,q+l,cmpid);
memcpy(a+l,q+l,sizeof(Dan)*(r-l+));
return;
}
int main()
{
//freopen("cnm.txt","r",stdin);
n=read();
for(int i=;i<=n;i++)
{
a[i].h=read();a[i].v=read();a[i].id=i;
wh[i]=a[i].h;wv[i]=a[i].v;
rk[i]=i;
}
sort(wh+,wh+n+);
sort(wv+,wv+n+);
th=unique(wh+,wh+n+)-wh-;
tv=unique(wv+,wv+n+)-wv-;
for(int i=;i<=n;i++)
{
a[i].h=th-(lower_bound(wh+,wh+th+,a[i].h)-wh)+;
a[i].v=tv-(lower_bound(wv+,wv+tv+,a[i].v)-wv)+;
}
sort(rk+,rk+n+,cmp);
for(int i=;i<=n;i++)a[rk[i]].t=i;
cdq(,n,);
for(int i=;i<=n;i++)
{
a[i].h=th-a[i].h+;
a[i].v=tv-a[i].v+;
a[i].id=n-a[i].id+;
a[i].t=n-a[i].t+;
}
reverse(a+,a+n+);
cdq(,n,);
reverse(a+,a+n+);
double smm=;
int ans=;
for(register int i=;i<=n;i++)
ans=max(ans,a[i].f[]+a[i].f[]-);
printf("%d\n",ans);
for(int i=;i<=n;i++)
if(a[i].f[]==ans)
smm+=a[i].g[]*a[i].g[]*1ll;
for(int i=;i<=n;i++)
{
double res=a[i].g[]*a[i].g[];
if(a[i].f[]+a[i].f[]-!=ans)printf("%.5lf ",0.0);
else printf("%.5f ",res/smm);
}
return ;
}

SDOI拦截导弹

///////这个专题的坑还很大,未完待续.........////////

dp杂题(根据个人进度选更)的更多相关文章

  1. wangkoala杂题总集(根据个人进度选更)

    CQOI2014 数三角形 首先一看题,先容斥一波,求出网格内选三个点所有的情况,也就是C(n*m,3);然后抛出行里三点共线的方案数:C(n,3)*m; 同理就有列中三点共线的方案数:n*C(m,3 ...

  2. 贪心/构造/DP 杂题选做Ⅱ

    由于换了台电脑,而我的贪心 & 构造能力依然很拉跨,所以决定再开一个坑( 前传: 贪心/构造/DP 杂题选做 u1s1 我预感还有Ⅲ(欸,这不是我在多项式Ⅱ中说过的原话吗) 24. P5912 ...

  3. 贪心/构造/DP 杂题选做Ⅲ

    颓!颓!颓!(bushi 前传: 贪心/构造/DP 杂题选做 贪心/构造/DP 杂题选做Ⅱ 51. CF758E Broken Tree 讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的 ...

  4. 贪心/构造/DP 杂题选做

    本博客将会收录一些贪心/构造的我认为较有价值的题目,这样可以有效的避免日后碰到 P7115 或者 P7915 这样的题就束手无策进而垫底的情况/dk 某些题目虽然跟贪心关系不大,但是在 CF 上有个 ...

  5. 【做题记录】DP 杂题

    P2577 [ZJOI2004]午餐 $\texttt{solution}$ 想到贪心: 吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序. 状态: \(f[i][j]\) 表示前 \(i\ ...

  6. 专题:DP杂题1

    A POJ 1018 Communication System B POJ 1050 To the Max C POJ 1083 Moving Tables D POJ 1125 Stockbroke ...

  7. 一些DP杂题

    1. [HNOI2001] 产品加工 一道简单的背包,然而我还是写了很久QAQ 时间范围是都小于5 显然考虑一维背包,dp[i]表示目前A消耗了i的最小B消耗 注意 if(b[i]) dp[j]=dp ...

  8. 【模拟8.01】matrix(DP杂题,思维题)

    很神的题,感谢lnc大佬的指点. 先设1-LL[i]统称左区间,RR[i]-m为右区间 用L[i]统计从1-i列,出现的左区间端点的前缀和,R[i]是右区间.... f[i][j]中j表示当前在第i列 ...

  9. DP杂题2

    1.邦邦的大合唱站队 https://www.luogu.org/problem/show?pid=3694 XY说这是道简单的签到题,然后我大概是普及组都拿不到三等的那种了.. 插入题解.写得太好了 ...

随机推荐

  1. 控制器向视图传参ModelAndView、Model和Map

    ModelAndView类 ModelAndView在spring-webmvc-4.3.18.RELEASE.jar包下,当然其他版本也有,所在包如下 对于那些返回String等类型的处理方法,sp ...

  2. 常用注解@Controller、@Service、@Autowired

    @Controller.@Service在spring-context-5.1.10.RELEASE.jar包下,所在包如下 @Autowired在spring-beans-5.1.10.RELEAS ...

  3. kubernetes垃圾回收器GarbageCollector源码分析(一)

    kubernetes版本:1.13.2 背景 由于operator创建的redis集群,在kubernetes apiserver重启后,redis集群被异常删除(包括redis exporter s ...

  4. CSS隐藏元素 display、visibility、opacity的区别

    关于使指定元素无法在视野内看到,有3个方法 display: none; opacity: 0; visibility: hidden; 1.display: none; 该方法会改变页面布局. 元素 ...

  5. 从零开始入门 K8s | Kubernetes 网络概念及策略控制

    作者 | 阿里巴巴高级技术专家  叶磊 一.Kubernetes 基本网络模型 本文来介绍一下 Kubernetes 对网络模型的一些想法.大家知道 Kubernetes 对于网络具体实现方案,没有什 ...

  6. Java应用在docker环境配置容器健康检查

    在<极速体验docker容器健康>一文已体验了docker容器健康检查功能,今天就来给java应用的容器加入健康检查,使应用的状态随时都可以被监控和查看. 实战环境信息 操作系统:macO ...

  7. Powershell基础之脚本执行

    Bat 这就是我们常用的Bat脚本,全名为批处理文件,脚本中就是我们在CMD中使用到的命令,这里提一个小问题:CMD的命令行执行命令的优先级是.bat > .exe,那么假如我放一个cmd.ba ...

  8. dnn文本分类

    简介 文本分类任务根据给定一条文本的内容,判断该文本所属的类别,是自然语言处理领域的一项重要的基础任务.具体的,本任务是对文本quey进行分类,任务流程如下: 收集用户query数据. 清洗,标记. ...

  9. Unity 登录白屏或者黑屏

    如果有一天,突然,你的Unity抽风了,登录界面白屏或者黑屏,不要急着重装.我重装了3次,第四次我再也忍不住了,终于出手了. 找到 C:\Users\hasee\AppData\Roaming\Uni ...

  10. StreamWriter 相关知识分享

    在介绍StreamWriter之前,我们首先来了解一下它的父类TextWriter. 一.TextWriter 1.TextWriter的构造函数和常用属性方法 下面是TextWriter的构造函数: ...