当前位置: 首页 > news >正文

AtCoder Educational DP Contest 刷题记录Ⅱ

H - Grid 1

原题链接:H - Grid 1

分析

二维动态规划,突然想起来小学奥数好像学过,不过奥数显然输入量没有这么大。

正解

#include <bits/stdc++.h>
#define mod 1000000007
using namespace std;
const int N = 1005;
int H, W;
char a[N][N];
int dp[N][N];
int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> H >> W;for (int i = 1; i <= H; i++){for (int j = 1; j <= W; j++){cin >> a[i][j];}}dp[1][1] = 1;for (int i = 2; i <= H; i++){dp[i][1] = (a[i][1] == '.') * dp[i - 1][1] % mod; }for (int j = 2; j <= W; j++){dp[1][j] = (a[1][j] == '.') * dp[1][j - 1] % mod; }for (int i = 2; i <= H; i++){for (int j = 2; j <= W; j++){if (a[i][j] == '#')dp[i][j] = 0;elsedp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod;}}cout << dp[H][W] % mod;
}

I - Coins

原题链接:I - Coins

分析

咋是绿了?写到绿的dp了/ll

好吧,蒟蒻并非会。

我们发现如果设dp_i表示掷前i个硬币正面朝上的硬币数多于反面朝上的硬币数的概率,几乎无法快速更新,所以多记录一维。

dp_{i,j}表示掷前i个硬币正面朝上的硬币数为j的概率。

转移

dp_{i,j}=dp_{i-1,j-1}\times p_i+dp_{i-1,j}\times (1-p_i)

依旧注意边界!

正解

#include <bits/stdc++.h>
using namespace std;
const int N = 3005;
int n;
double p[N], q[N];
double dp[N][N];
int main(){cin >> n;for (int i = 1; i <= n; i++){cin >> p[i];q[i] = 1.0 - p[i];}dp[0][0] = 1.0;dp[1][1] = p[1];dp[1][0] = q[1];for (int i = 2; i <= n; i++){for (int j = 0; j <= i; j++){dp[i][j] = dp[i - 1][j - 1] * p[i] + dp[i - 1][j] * q[i];}}double ans = 0;for (int j = (n + 1) / 2; j <= n; j++){ans += dp[n][j];}cout << fixed << setprecision(10) << ans;
}

J - Sushi

原题链接:J - Sushi

分析

我要补概率了。

正解

#include <bits/stdc++.h>
using namespace std;
const int N = 305;
double dp[N][N][N];
int cnt[5];
double n;
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n; i++){int tmp;cin >> tmp;cnt[tmp]++;}for (int k = 0; k <= n; k++){for (int j = 0; j <= n; j++){for (int i = 0; i <= n; i++){if (i)dp[i][j][k] += dp[i - 1][j][k] * i / (i + j + k + 0.0);if (j)dp[i][j][k] += dp[i + 1][j - 1][k] * j / (i + j + k + 0.0);if (k)dp[i][j][k] += dp[i][j + 1][k - 1] * k / (i + j + k + 0.0);if (i || j || k)dp[i][j][k] += n / (i + j + k + 0.0);}}}cout << fixed << setprecision(15) << dp[cnt[1]][cnt[2]][cnt[3]];
}

K - Stones

原题链接:K - Stones

分析

博……博弈论?这不是DP吗?

确实是 DP,甚至是背包的变种。我们考虑若一个人选了第k-a_j个,那么必输。

所以我们设dp_i=0/1表示有i个石子后手/先手赢。那么,只有当dp_{i-a_j}值可以更新对方。

那么,就可以写代码了。

黄题写不出来,我是**/(ㄒoㄒ)/~~

正解

#include <bits/stdc++.h>
using namespace std;
const int N = 105, K = 100005;
int n, k, a[N];
bool dp[K];
int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> k;for (int i = 1; i <= n; i++){cin >> a[i];}for (int i = 1; i <= k; i++){for (int j = 1; j <= n; j++){if (i - a[j] >= 0){if (!dp[i - a[j]])dp[i] = 1;}}}if (dp[k])cout << "First";elsecout << "Second";
}

L - Deque

原题链接:L - Deque

分析

还在博弈/ll

所以,DP模拟博弈过程是我们需要掌握的。

dp_{l,r}表示剩余区间[l,r]先手能取得的最大分差。

则,\left\{\begin{matrix} dp_{l,r}=max(dp_{i+1,j}+a_i, dp_{i,j-1}+a_j),(n-(j-i+1)\equiv 0\pmod2) \\ dp_{l,r}=min(dp_{i+1,j}-a_i,dp_{i,j-1}-a_j),(n-(j-i+1)\equiv 1\pmod2) \end{matrix}\right.

正解

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3005;
int n, a[N], f[N][N];
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];}for (int len = 1; len <= n; len++){for (int l = 1; l + len - 1 <= n; l++){int r = l + len - 1;if ((n - len) % 2 == 1){f[l][r] = min(f[l + 1][r] - a[l], f[l][r - 1] - a[r]);}else{f[l][r] = max(f[l + 1][r] + a[l], f[l][r - 1] + a[r]);}}}cout << f[1][n];
} 

M - Candies

原题链接:M - Candies

分析

优化想不到可以理解,但是这么简单的状态没盯出来应该反思。

dp_{i,j}表示考虑前i个孩子,恰好分完j个糖果的方案数。

考虑转移,dp_{i,j}=\sum_{x=0}^{a_i}dp_{i-1,j-x},复杂度O(n^2k).

考虑优化,前缀和!设sum_{i,j}=\sum_{x=0}^{j}dp_{i,j}

转移方程:dp_{i,j}=sum_{i-1,j}-sum_{i-1,j-a_i-1}\\sum_{i,j}=sum_{i,j-1}+dp_{i,j}

正解

#include <bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
const int N = 105, K = 100005;
int n, k, a[N];
long long sum[N][K], dp[N][K];
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> k;for (int i = 1; i <= n; i++){cin >> a[i];}dp[1][0] = sum[1][0] = 1;for (int i = 1; i <= k; i++){dp[1][i] = (i <= a[1]);sum[1][i] = dp[1][i] + sum[1][i - 1];}for (int i = 2; i <= n; i++){dp[i][0] = sum[i][0] = 1;for (int j = 1; j <= k; j++){if (j <= a[i])dp[i][j] = sum[i - 1][j] % mod;elsedp[i][j] = (sum[i - 1][j] - sum[i - 1][j - a[i] - 1] + mod) % mod;sum[i][j] = (sum[i][j - 1] + dp[i][j]) % mod;}}cout << dp[n][k];
}

N - Slimes

原题链接:N - Slimes

分析

AT版石子合并?甚至不是环形……好吧数组开小了。

正解

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 405;
int n, m[405];
long long sum[405], f[N][N];
signed main(){cin >> n;memset(f, 0x3f, sizeof(f));for (int i = 1; i <= n; i++){cin >> m[i];sum[i] = sum[i - 1] + m[i];f[i][i] = 0;} for (int len = 1; len < n; len++){for (int l = 1; l + len <= n; l++){int r = l + len;for (int k = l; k <= r; k++){f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r]);}f[l][r] += sum[r] - sum[l - 1];}}cout << f[1][n];
}

P - Independent Set

原题链接:P - Independent Set

别问为啥没有O,蒟蒻没学状压DP,不会/ll,幸运的是,这周末有老师讲!

分析

树形DP,当我以为这题可以降黄被我切掉的时候,审题给我当头一棒!

Here, it is not allowed to paint two adjacent vertices both in black.

看成不允许相邻颜色相同了,我是**/(ㄒoㄒ)/~~

正解

#include <bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
const int N = 100005;
int n, x, y;
vector<int> e[N];
int f[N][2];
void dfs(int u, int fa){f[u][0] = f[u][1] = 1;for (auto v : e[u]){if (v == fa)continue;dfs(v, u);f[u][0] = f[u][0] * ((f[v][0] + f[v][1]) % mod) % mod;f[u][1] = f[u][1] * f[v][0] % mod;}
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i < n; i++){cin >> x >> y;e[x].push_back(y);e[y].push_back(x);}dfs(1, 0);cout << (f[1][0] + f[1][1]) % mod;
}

Q - Flowers

原题链接:Q - Flowers

分析

第一眼以为是单调栈优化DP,但细想一下,找到前面一个比它高度小的不见得价值足够大。所以,这是一道线段树/树状数组优化DP,该来的终究还是来了/ll

由于线段树通用性更好,所以我们写线段树。

我们设dp_i表示以第i个元素结尾的价值最大的子序列,

考虑转移,dp_i=max\left \{ dp_j|h_j\leq h_i\right \}+a_i

线段树维护区间最大值即可。

正解

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, h[N], a[N];
long long dp[N];
struct segtree{long long maxn[N << 2];void pushup(int p){maxn[p] = max(maxn[p << 1], maxn[p << 1 | 1]);}void modify(int p, int l, int r, int pos, long long k){if (l == r){maxn[p] = max(maxn[p], k);return ;}int mid = (l + r) >> 1;if (pos <= mid)modify(p << 1, l, mid, pos, k);elsemodify(p << 1 | 1, mid + 1, r, pos, k);pushup(p);}long long query(int p, int l, int r, int s, int t){if (s > t) return 0;if (s <= l && r <= t){return maxn[p];}int mid = (l + r) >> 1;long long ans = 0;if (s <= mid)ans = max(ans, query(p << 1, l, mid, s, t));if (t > mid)ans = max(ans, query(p << 1 | 1, mid + 1, r, s, t));return ans;}
}T;
int main(){ios::sync_with_stdio(0);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++){cin >> h[i];}for (int i = 1; i <= n; i++){cin >> a[i];}for (int i = 1; i <= n; i++){long long maxn = T.query(1, 1, n, 1, h[i] - 1);dp[i] = maxn + a[i];T.modify(1, 1, n, h[i], dp[i]);}cout << T.query(1, 1, n, 1, n);return 0;
}
http://www.dtcms.com/a/581661.html

相关文章:

  • 如何构建以数据驱动的现代软件架构
  • 如何禁止Chrome的重新启动即可更新窗口弹窗提示
  • 爱用建站 小程序镇江网站制作优化
  • 在Ubuntu中下载gcc
  • 杰理蓝牙耳机开发 -- SPP功能开发与应用
  • 【锦州通APP注册_登录安全-无验证方式导致安全隐患】
  • 网站建设属于哪个类目淘宝网站开发费用
  • Socket vs WebSocket
  • Java中BufferedImage转byte[]字节数组
  • day10 鹏哥C语言 操作符
  • 推广平台网站聊城网站建设推广
  • 政策东风下:卓玛儿童级健康腻子引领行业升级
  • Azure Storage Discovery(国际版)正式发布
  • 4、prometheus-服务发现k8s api-2
  • 立冬节气科学调养身心
  • 安徽省建设行业质量与安全协会网站网站建设拓客有什么方法
  • 【XR开发系列】2025 年 XR 开发入门,我该选择 Unity 还是 Unreal Engine?
  • 在wps软件的word中使用js宏命令设置表格背景色
  • 怎样写网站文案零食网站建设前的市场分析
  • 环保网站建设的主题七牛部署WordPress
  • (八)嵌入式面试题收集:8道
  • 【App开发】04:Android Studio第一个项目之页面开发
  • Client port found: 2181. Client address: localhost. Client SSL: false.
  • 用ffmpeg来压缩视频文件
  • ABAP+在select的时候,可以A=B A=C B=C这样子JOIN吗?
  • 网站概要设计模板做网站体会心得
  • 零基础入门C语言之C语言实现数据结构之顺序表
  • Nine.fun携MasterPay共建Web3现实支付桥梁
  • 图像处理中的暗场校正
  • WPS Office国际版 办公软件v18.20.2完美去广解锁高级版