dp 杂题

T1:消失之物

题干:

  $ftiasch$ 有 $N$ 个物品, 体积分别是 $W_1, W_2, ..., W_N$。 由于她的疏忽, 第 $i$ 个物品丢失了。 “要使用剩下的 $N - 1$ 物品装满容积为 $x$ 的背包,有几种方法呢?” -- 这是经典的问题了。

  她把答案记为 $Count(i, x)$ ,想要得到所有 $1 <= i <= N$, $1 <= x <= M$ 的 $Count(i, x)$ 表格。 

  输入格式:

  第 $1$ 行:两个整数 $N$ $(1 ≤ N ≤ 2 × 10^3)$ 和 $M$ $(1 ≤ M ≤ 2 × 10^3)$,物品的数量和最大的容积。

  第 $2$ 行: $N$ 个整数 $W_1, W_2, ..., W_N$ , 物品的体积。

  输出格式: 一个 $N × M$ 的矩阵, $Count(i, x)$ 的末位数字

题解:

  

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #define $ 3111
 5 #define int long long
 6 using namespace std;
 7 int m,n,k,t,dp[$],v[$],g[$];
 8 signed main(){
 9     scanf("%lld%lld",&n,&m);    
10     for(register int i=1;i<=n;++i) scanf("%lld",&v[i]);
11     dp[0]=1;
12     for(register int i=1;i<=n;++i)
13         for(register int j=m;j>=v[i];--j) dp[j]=(dp[j]+dp[j-v[i]])%10;
14     for(register int i=1;i<=n;++i){
15         for(register int j=0;j<=m;++j)    g[j]=dp[j]%10;
16         for(register int j=v[i];j<=m;++j) g[j]=(g[j]-g[j-v[i]])%10;
17         for(register int j=1;j<=m;++j) 
18             printf("%lld",(g[j]%10+10)%10);  puts("");
19     }
20 }
View Code

T2:方伯伯的玉米田

题干:

  方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美。

  这排玉米一共有 $N$ 株,它们的高度参差不齐。

  方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列。

  方伯伯可以选择一个区间,把这个区间的玉米全部拔高 $1$ 单位高度,他可以进行最多 $K$ 次这样的操作。拔玉米则可以随意选择一个集合的玉米拔掉。

  问能最多剩多少株玉米,来构成一排美丽的玉米。

  输入格式:

  第 $1$ 行包含 $2$ 个整数 $n$,$K$,分别表示这排玉米的数目以及最多可进行多少次操作。

  第 $2$ 行包含n个整数,第 $i$ 个数表示这排玉米,从左到右第 $i$ 株玉米的高度 $a_i$。

  输出格式:输出 $1$ 个整数,最多剩下的玉米数。

题解:

  这道题有一个小贪心:若在 x 号节点使用操作,让 n 号节点作为右端点一定不劣。

  (若右端点不在 n 节点处,而在 y 节点处,那么)

  这道题一开始只能想到 $\Theta(n^2k^2)$ 的暴力,交上去才发现一个小测试点也没有。。。

  在 $\Theta(n^2k^2)$ 的暴力中,有一个十分显然的 dp 式:(边转移边更新答案)

$\sum\limits_{i=1}^{n}\sum\limits_{j=0}^{k}dp[i][j]=\sum\limits_{l=1}^{i-1}\sum\limits_{r=0}^{j-1}\max(dp[l][r])+1$

  我们发现在等式右侧,我们找的是一个矩阵的最大值,可以想到用二维树状数组来维护。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #define int long long
 4 #define $ 505
 5 using namespace std;
 6 int n,k,dp[$*20][$],a[$*20],tr[$*20][$],ans,maxx;
 7 inline int max(int x,int y){    return x>y?x:y;    }
 8 inline void add(int x,int y,int add){
 9     for(register int i=x;i<=maxx+k;i+=i&(-i))
10         for(register int j=y;j<=k+1;j+=j&(-j)) tr[i][j]=max(tr[i][j],add); 
11 }
12 inline int ask(int x,int y,int ans=0){
13     for(register int i=x;i>=1;i-=i&(-i))
14         for(register int j=y;j>=1;j-=j&(-j)) ans=max(tr[i][j],ans);
15     return ans;
16 }
17 signed main(){
18     scanf("%d%d",&n,&k);
19     for(register int i=1;i<=n;++i) 
20         scanf("%d",&a[i]), maxx=max(maxx,a[i]);
21     for(register int i=1;i<=n;++i){
22         for(register int j=k;j>=0;--j){
23             dp[i][j]=ask(a[i]+j,j+1)+1, ans=max(ans,dp[i][j]);
24             add(a[i]+j,j+1,dp[i][j]);
25         }
26     }
27     printf("%d\n",ans);
28 }
View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #define int long long
 4 #define $ 501
 5 using namespace std;
 6 int n,k,dp[$*20][$],a[$*20],tr[$*21][$],ans,maxx;
 7 inline int max(int x,int y){    return x>y?x:y;    }
 8 inline void add(int x,int y,int add){
 9     for(register int i=x;i<=maxx+k;i+=i&(-i))
10         for(register int j=y;j<=k+1;j+=j&(-j)) tr[i][j]=max(tr[i][j],add); 
11 }
12 inline int ask(int x,int y,int ans=0){
13     for(register int i=x;i>=1;i-=i&(-i))
14         for(register int j=y;j>=1;j-=j&(-j)) ans=max(tr[i][j],ans);
15     return ans;
16 }
17 signed main(){
18     scanf("%d%d",&n,&k);
19     for(register int i=1;i<=n;++i) 
20         scanf("%d",&a[i]), maxx=max(maxx,a[i]);
21     for(register int i=1;i<=n;++i){
22         for(register int j=0;j<=k;++j) 
23             dp[i][j]=ask(a[i]+j,j+1)+1, ans=max(ans,dp[i][j]);
24         for(register int j=0;j<=k;++j) add(a[i]+j,j+1,dp[i][j]);
25     }
26     printf("%d\n",ans);
27 }
View Code

T3:拦截导弹

题干:

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

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

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

  输入格式:

  第一行包含一个正整数 $n$,表示敌军导弹数量;

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

  第 $i+1$ 行包含 $2$ 个正整数 $h_i$ 和 $v_i$ ,分别表示第 $i$ 枚导弹的高度和速度。

  输出格式:

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

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

题解:

  

Code:

 

T1:

题干:

 

题解:

 

Code:

 

 

T1:

题干:

 

题解:

 

Code:

 

 

T1:

题干:

 

题解:

 

Code:

 

 

猜你喜欢

转载自www.cnblogs.com/OI-zzyy/p/11272928.html