Atcoder Educational DP Contest 题解
A - Frog 1/B - Frog 2
入门...
#include<cstdio>
#define abs(a) ((a)>=0?(a):(-(a)))
#define min(a,b) ((a)<(b)?(a):(b))
#define maxn 100050
using namespace std;
int dp[maxn],a[maxn];
int main(){
int n,k=;
scanf("%d",&n);
for (int i=;i<=n;i++)
scanf("%d",&a[i]),dp[i]=1e9;
dp[]=;
for (int i=;i<=n;i++){
for (int j=;j<=k;j++)
if (i-j>) dp[i]=min(dp[i],dp[i-j]+abs(a[i-j]-a[i]));
}
printf("%d\n",dp[n]);
return ;
}
A and B
C - Vacation
$dp[i][0/1/2]$ 表示到第 $i$ 个 这一个选 $0/1/2$ 转移就很显然了....
#include<cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 100050
using namespace std;
int dp[maxn][];
int main(){
int n;
scanf("%d",&n);
for (int i=;i<=n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
dp[i][]=max(dp[i-][],dp[i-][])+a;
dp[i][]=max(dp[i-][],dp[i-][])+b;
dp[i][]=max(dp[i-][],dp[i-][])+c;
}
printf("%d\n",max(max(dp[n][],dp[n][]),dp[n][]));
return ;
}
C
D - Knapsack 1
裸背包
#include<cstdio>
#define ll long long
#define max(a,b) (a>b?a:b)
#define maxn 100050
using namespace std;
ll dp[maxn];
int main(){
int n,W;
scanf("%d%d",&n,&W);
for (int i=;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
for (int j=W;j>=a;j--)
dp[j]=max(dp[j-a]+b,dp[j]);
}
ll ans=;
for (int j=;j<=W;j++)
if (dp[j]>ans) ans=dp[j];
printf("%lld\n",ans);
return ;
}
D
E - Knapsack 2
发现价值比较小,那么换一下 $dp$ 的状态表示
$dp[j]$ 表示价值为 $j$ 的最小重量
答案就从大到小枚举 $\leq W$ 的即可。
#include<cstdio>
#define ll long long
#define max(a,b) (a>b?a:b)
#define maxn 100050
#define min(a,b) (a<b?a:b)
using namespace std;
ll dp[maxn];
int main(){
int n,W;
scanf("%d%d",&n,&W);
for (int j=;j<=1e5;j++)
dp[j]=1e12;
for (int i=;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
for (int j=1e5;j>=b;j--)
dp[j]=min(dp[j-b]+a,dp[j]);
}
for (int i=1e5;i>=;i--)
if (dp[i]<=W) return printf("%d\n",i),;
return ;
}
/*
dp[i][j]表示前i个价值和为j的最小重量
*/
E
F - LCS
裸的最长公共子序列...方案存一下转移路径倒推就好了
#include<cstdio>
#include<cstring>
#define maxn 3005
using namespace std;
int dp[maxn][maxn],last[maxn][maxn];
char s[maxn],t[maxn],w[maxn];
int main(){
scanf("%s%s",s+,t+);
int n=strlen(s+),m=strlen(t+);
for (int i=;i<=n;i++)
for (int j=;j<=m;j++){
if (s[i]==t[j]) {
if (dp[i][j]<dp[i-][j-]+) dp[i][j]=dp[i-][j-]+,last[i][j]=;
}
if (dp[i-][j]>dp[i][j]) dp[i][j]=dp[i-][j],last[i][j]=;
if (dp[i][j-]>dp[i][j]) dp[i][j]=dp[i][j-],last[i][j]=;
}
int x=n,y=m;
while (dp[x][y]){
if (last[x][y]==) w[dp[x][y]]=s[x],x--,y--;else
if (last[x][y]==) x--;else y--;
}
for (int i=;i<=dp[n][m];i++)
printf("%c",w[i]);
printf("\n");
return ;
}
F
G - Longest Path
最长路径,拓扑上dp
#include<cstdio>
#define maxn 100050
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
struct enode{
int nxt,y;
}e[maxn];
int ans=,tot=;
int n,m;
int q[maxn],dp[maxn],first[maxn],goin[maxn];
void adde(int x,int y){
e[tot].nxt=first[x];
e[tot].y=y;
first[x]=tot++;
goin[y]++;
}
void tupu(){
int head=,tail=;
for (int i=;i<=n;i++)
if (!goin[i]) q[++tail]=i;
while (head<=tail){
int x=q[head++];
if (dp[x]>ans) ans=dp[x];
for (int i=first[x];i>=;i=e[i].nxt){
int y=e[i].y;
goin[y]--;
dp[y]=max(dp[x]+,dp[y]);
if (!goin[y]) q[++tail]=y;
}
}
}
int main(){ scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
first[i]=-;
for (int i=;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
adde(x,y);
}
tupu();
printf("%d\n",ans);
return ;
}
G
H - Grid 1
唔...入门dp吧QAQ
#include<cstdio>
#define HR 1000000007
using namespace std;
char s[];
int dp[][];
int main(){
int n,m;
scanf("%d%d",&n,&m);
dp[][]=;
for (int i=;i<=n;i++){
scanf("%s",s+);
for (int j=;j<=m;j++)
if ((i!=||j!=)&&(s[j]!='#')) dp[i][j]=(dp[i-][j]+dp[i][j-])%HR;
}
printf("%d\n",dp[n][m]);
return ;
}
H
I - Coins
概率dp
$dp[i][j]$ 表示前 $i$ 个有 $j$ 个向上的概率
那么对于当前这一个 要不然就向上 要不然就向下
$dp[i][j]=dp[i-1][j-1]*p[i]+dp[i-1][j]*(1-p[i])$
#include<cstdio>
using namespace std;
double p[],dp[][];
int main(){
int n;
scanf("%d",&n);
for (int i=;i<=n;i++)
scanf("%lf",&p[i]);
dp[][]=;
for (int i=;i<=n;i++){
dp[i][]=dp[i-][]*(-p[i]);
for (int j=;j<=i;j++)
dp[i][j]=dp[i-][j-]*p[i]+dp[i-][j]*(-p[i]);
} double ans=;
for (int i=;i<=n;i++)
if (i>n-i) ans+=dp[n][i];
printf("%.10lf\n",ans);
return ;
}
I
J - Sushi
期望dp
$dp[i][j][k]$ 表示 $1$ 有 $i$ 个,$2$ 有 $j$ 个,$3$ 有 $k$ 个的期望
$dp[i][j][k]=dp[i-1][j][k]\times \frac{i}{n}+dp[i+1][j-1][k]\times \frac{j}{n}+dp[i][j+1][k-1]\times \frac{k}{n}+dp[i][j][k]\times \frac{n-i-j-k}{n}+1$
$dp[i][j][k]\times \frac{i+j+k}{n}=dp[i-1][j][k]\times \frac{i}{n}+dp[i+1][j-1][k]\times \frac{j}{n}+dp[i][j+1][k-1]\times \frac{k}{n}+1$
$dp[i][j][k]\times(i+j+k)=dp[i-1][j][k]\times i+dp[i+1][j-1][k]\times j+dp[i][j+1][k-1]\times k+n$
$dp[i][j][k]=dp[i-1][j][k]\times \frac{i}{i+j+k}+dp[i+1][j-1][k]\times \frac{j}{i+j+k}+dp[i][j+1][k-1]\times \frac{k}{i+j+k}+\frac{n}{i+j+k}$
#include<cstdio>
using namespace std;
double dp[][][];
int a[];
int main(){
int n;
scanf("%d",&n);
for (int i=;i<=n;i++){
int x;
scanf("%d",&x);
a[x]++;
}
for (int k=;k<=n;k++)
for (int j=;j<=n;j++)
for (int i=;i<=n;i++)
if (i||j||k) {
if (i) dp[i][j][k]+=dp[i-][j][k]*i/(i+j+k);
if (j) dp[i][j][k]+=dp[i+][j-][k]*j/(i+j+k);
if (k) dp[i][j][k]+=dp[i][j+][k-]*k/(i+j+k);
dp[i][j][k]+=(double)n/(i+j+k);
}
printf("%.15lf\n",dp[a[]][a[]][a[]]);
return ;
} /*
dp[i][j][k]表示当前有i个1 j个2 k个3 的期望步数 dp[0][0][0]=0 dp[i][j][k]=dp[i-1][j][k]*i/n+dp[i+1][j-1][k]*j/n+dp[i][j+1][k-1]*k/n+dp[i][j][k]*(n-i-j-k)/n+1
dp[i][j][k]*(i+j+k)/n=dp[i-1][j][k]*i/n+dp[i+1][j-1][k]*j/n+dp[i][j+1][k-1]*k/n+1
dp[i][j][k]*(i+j+k)=dp[i-1][j][k]*i+dp[i+1][j-1][k]*j+dp[i][j+1][k-1]*k+n
dp[i][j][k]=dp[i-1][j][k]*i/(i+j+k)+dp[i+1][j-1][k]*j/(i+j+k)+dp[i][j+1][k-1]*k/(i+j+k)+n/(i+j+k) */
J
Atcoder Educational DP Contest 题解的更多相关文章
- Atcoder Educational DP Contest I - Coins (概率DP)
题意:有\(n\)枚硬币,每枚硬币抛完后向上的概率为\(p[i]\),现在求抛完后向上的硬币个数大于向下的概率. 题解:我们用二维的\(dp[i][j]\)来表示状态,\(i\)表示当前抛的是第\(i ...
- AtCoder Educational DP Contest 总结
前言 感觉都初一升初二了,再做这个题是不是有点太菜了啊-- 里面大概都是些 DP 板子题(确信,题目质量还挺高的,不过不涉及太难的优化(实际上只有最后一题是斜率优化). 不管了,还是写个 blog 来 ...
- Atcoder Educational DP Contest
前面简单一点的题直接过吧. A 暴力DP B 怎么还是暴力DP C 还是暴力DP D 直接背包 E 这个背包不太一样了,这里有一个技巧,就是因为价值很小,所以直接对价值背包,求出来达到某一个权值最小的 ...
- Sth about Educational DP Contest
Contest Website : atcoder.jp/contests/dp \[\begin{array}{c|C|c|c} TaskNum & TaskName & Statu ...
- Educational DP Contest H - Grid 1 (DP)
题意:有一个\(n\)X\(m\)的图,"#"表示障碍物,"."表示道路,只能向右或向下走,问从左上角走到右下角的方案数. 题解:这题可以用bfs来搞,但dp更 ...
- Educational DP Contest G - Longest Path (dp,拓扑排序)
题意:给你一张DAG,求图中的最长路径. 题解:用拓扑排序一个点一个点的拿掉,然后dp记录步数即可. 代码: int n,m; int a,b; vector<int> v[N]; int ...
- Educational DP Contest F - LCS (LCS输出路径)
题意:有两个字符串,求他们的最长公共子序列并输出. 题解:首先跑个LCS记录一下dp数组,然后根据dp数组来反着还原路径,只有当两个位置的字符相同时才输出. 代码: char s[N],t[N]; i ...
- Educational DP Contest E - Knapsack 2 (01背包进阶版)
题意:有\(n\)个物品,第\(i\)个物品价值\(v_{i}\),体积为\(w_{i}\),你有容量为\(W\)的背包,求能放物品的最大价值. 题解:经典01背包,但是物品的最大体积给到了\(10^ ...
- 【DP】Educational DP Contest
这份 dp 题单的最后几题好难 orz. 前面的题比较简单,所以我会选取一些题来讲,其它的直接看代码理解吧 qwq. 传送门: https://atcoder.jp/contests/dp 全部 AC ...
随机推荐
- mysql/mariadb数据库在插入表数据时,ID竟然成奇数增加了?看完下面内容就知道怎么处理了。
今天突然被问到一个问题,mysql数据库插入表数据时,设置了ID自增,但是插入数据后,ID却呈奇数增加,不是123456类型,而是13579形式,突然有点懵,研究了一会,发现是auto_increme ...
- Linux 之 netstat使用
netstat介绍 Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast ...
- leetcode548 Split Array with Equal Sum
思路: 使用哈希表降低复杂度.具体来说: 枚举j: 枚举i,如果sum[i - 1] == sum[j - 1] - sum[i],就用哈希表把sum[i - 1]记录下来: 枚举k,如果sum[k ...
- NOIP 2015:信息传递
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- PTA(Advanced Level)1037.Magic Coupon
The magic shop in Mars is offering some magic coupons. Each coupon has an integer N printed on it, m ...
- 【转贴】内存重要参数详解 RAS CAS
内存重要参数详解 RAS CAS 分类: LINUX 2014-09-12 09:41:58 原文地址:内存重要参数详解 RAS CAS 作者:Reny http://blog.chinaunix.n ...
- JVM学习(一)Java虚拟机运行时数据区域
一.Java内存区域 1.运行时数据区域 根据<Java 虚拟机规范(Java SE 7 版)>规定,Java 虚拟机所管理的内存包括以下几个运行时数据区域: 1.1 程序计数器 程序计数 ...
- (十六)JDBC 处理大数据
目录 前言: 基本概念 对于Mysql的Text类型 流地址的写法 blob类型数据 备注 前言: 在实际开发中,程序需要把 大文本或二进制 数据保存到数据库中: 实际上,我们并不存储大的数据到数据库 ...
- swiper手滑动轮播图后自动轮播失效解决办法
设置autoplay:true之后,再设置 autoplay:{disableOnInteraction: false} --------------------------------------- ...
- python — 装饰器、迭代器
目录 1 装饰器 2 迭代器 3 可迭代对象 1 装饰器 1.1目的.应用场景: 目的: 在不改变原函数内部代码的基础上,在函数执行前后自定义功能. 应用场景: 想要为函数扩展功能时,可以选择用装饰器 ...