【做题笔记】Atcoder 之 dp 专题训练
A#
B#
C#
D#
E#
F#
G#
H#
I#
概率 dp。
设
当
初始化
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 3005;
double ans, p[N], dp[N][N];
int n;
signed main() {
cin >> n;
For(i,1,n) cin >> p[i];
dp[0][0] = 1;
For(i,1,n) {
For(j,0,i) {
if(j == 0) dp[i][j] = dp[i-1][j] * (1 - p[i]);
else dp[i][j] = dp[i-1][j-1] * p[i] + dp[i-1][j] * (1 - p[i]);
}
}
For(i,n/2+1,n) {
ans += dp[n][i];
}
printf("%.10lf\n", ans);
return 0;
}
J#
K#
博弈论 dp。
设
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 105, M = 2e5 + 10;
int n, k, a[N];
bool dp[M];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
For(i,1,n) cin >> a[i];
For(j,0,k) {
For(i,1,n) {
if(a[i] <= j) dp[j] |= (dp[j-a[i]] == 0);
}
}
cout << (dp[k] ? "First\n" : "Second\n");
return 0;
}
L#
M#
数数 dp。
设
答案为
上者使用前缀和优化即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;ri>=l;--i)
#define mod 1000000007
using namespace std;
const int N = 105, M = 1e5 + 10;
int n, K, a[N], dp[N][M], sum[N][M];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> K;
For(i,1,n) cin >> a[i];
dp[0][0] = sum[0][0] = 1;
For(i,1,K) sum[0][i] += sum[0][i-1];
For(i,1,n) {
For(j,0,K) {
if(j == min(j,a[i])) dp[i][j] = sum[i-1][j] ;
else dp[i][j] = (sum[i-1][j] - sum[i-1][j-min(j,a[i])-1] + mod) % mod;
sum[i][j] = (sum[i][j-1] + dp[i][j]) % mod;
}
}
cout << dp[n][K] << '\n';
return 0;
}
N#
O#
状压 dp。
设
答案为
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 1000000007
using namespace std;
const int N = 22, M = (1<<22)+1;
int n, a[N][N], dp[N][M], to[N][N], len[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) {
For(j,1,n) {
cin >> a[i][j];
if(a[i][j]) {
to[i][++len[i]] = j;
}
}
}
dp[0][0] = 1;
For(i,1,n) {
For(j,1,len[i]) {
int x = to[i][j]-1;
for (int S = 0; S < (1<<n); S++) {
if((S >> x) & 1) {
dp[i][S] = (dp[i][S] + dp[i-1][S ^ (1 << x)]) % mod;
}
}
}
}
cout << dp[n][(1<<n)-1] << '\n';
return 0;
}
P#
数数 dp,类似 没有上司的舞会
设
答案为
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 1000000007
using namespace std;
const int N = 1e5 + 10;
struct Node {
int v, nx;
} e[N << 1];
int n, h[N], tot, dp[N][2];
void add(int u, int v) {
e[++tot] = (Node){v, h[u]};
h[u] = tot;
}
void dfs(int x, int fa) {
dp[x][0] = dp[x][1] = 1;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
if(y == fa) continue;
dfs(y, x);
dp[x][0] = (dp[x][0] * (dp[y][0] + dp[y][1]) % mod) % mod;
dp[x][1] = (dp[x][1] * dp[y][0]) % mod;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n-1) {
int u, v;
cin >> u >> v;
add(u, v); add(v, u);
}
dfs(1, 0);
cout << (dp[1][0] + dp[1][1]) % mod;
return 0;
}
Q#
带权最长上升子序列
设
维护
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 1000000007
using namespace std;
const int N = 2e5 + 10;
int n, h[N], a[N], t[N], dp[N], ans;
int lb(int x) {
return x & -x;
}
void add(int x, int val) {
for (int i = x; i <= N-2; i += lb(i)) {
t[i] = max(t[i], val);
}
}
int Max(int x) {
int res = 0;
for (int i = x; i; i -= lb(i)) {
res = max(res, t[i]);
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> h[i];
For(i,1,n) cin >> a[i];
For(i,1,n) {
dp[i] = Max(h[i]-1) + a[i];
add(h[i], dp[i]);
ans = max(ans, dp[i]);
}
cout << ans << '\n';
return 0;
}
R#
矩阵优化 dp。
设
答案为
可以发现每一次 sigma 内的转移都是固定的,这样重复有规律的转移可以用矩阵快速幂进行优化。
设计矩阵
对此矩阵进行
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 1000000007
using namespace std;
const int N = 55;
int n, k, a[N][N], ans;
struct Matrix {
int M[N][N];
void clear() {
For(i,1,n) For(j,1,n) M[i][j] = 0;
}
void init() {
clear();
For(i,1,n) M[i][i] = 1;
}
Matrix friend operator * (const Matrix &A, const Matrix &B) {
Matrix Ans;
Ans.clear();
For(i,1,n) {
For(j,1,n) {
For(k,1,n) {
Ans.M[i][j] = (Ans.M[i][j] + (A.M[i][k] * B.M[k][j]) % mod) % mod;
}
}
}
return Ans;
}
} dp;
Matrix qpow(Matrix a, int b) {
Matrix res; res.init();
for (; b; b >>= 1, a = a * a) {
if(b & 1) res = res * a;
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
For(i,1,n) For(j,1,n) cin >> a[i][j];
For(i,1,n) For(j,1,n) dp.M[i][j] = a[j][i];
Matrix Res; Res.clear();
For(i,1,n) Res.M[i][1] = 1;
Res = qpow(dp, k) * Res;
For(i,1,n) ans = (ans + Res.M[i][1]) % mod;
cout << ans << '\n';
return 0;
}
S#
数位 dp。
设
考虑记忆化搜索,每位数值从
上限的判定为从高位至低位的前缀一致(
答案满足要求显然就是
以上为搜索统计答案,只要记忆化一下即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 1000000007
using namespace std;
const int N = 1e5 + 10, D = 105;
string k;
int n, d, num[N], dp[N][D][2];
int dfs(int pos, int res, int lim) {
if(pos == 0) return (res == 0);
if(dp[pos][res][lim] != -1) return dp[pos][res][lim];
int ans = 0, maxx = (lim ? num[pos] : 9);
For(i,0,maxx) {
ans = (ans + dfs(pos - 1, (res + i) % d, lim && (i == maxx))) % mod;
}
return dp[pos][res][lim] = ans;
}
int ans() {
memset(dp, -1, sizeof dp);
For(i,1,n) num[i] = k[n-i+1] - '0';
return dfs(n, 0, 1);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> k >> d;
n = k.size();
k = " " + k;
cout << (ans()-1+mod)%mod << '\n';
return 0;
}
T#
数数 dp。
设
当
当
答案为
使用前缀和优化即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 1000000007
using namespace std;
const int N = 3e3 + 10;
int n, dp[N][N], sum[N][N];
char s[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
cin >> s + 2;
dp[1][1] = sum[1][1] = 1;
For(i,2,n) {
For(j,1,i) {
if(s[i] == '<') dp[i][j] = sum[i-1][j-1];
else dp[i][j] = (sum[i-1][i-1] - sum[i-1][j-1] + mod) % mod;
sum[i][j] = (sum[i][j-1] + dp[i][j]) % mod;
}
}
int ans = 0;
For(i,1,n) ans = (ans + dp[n][i]) % mod;
cout << ans << '\n';
return 0;
}
U#
看题解做出来的...
状压 dp。
设
则转移为:
答案为:
时间复杂度为
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 17, M = (1<<17);
int n, a[N][N], val[M], dp[M];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,0,n-1) For(j,0,n-1) cin >> a[i][j];
For(S,0,(1<<n)-1) {
For(i,0,n-1) {
For(j,0,i-1) {
if(((S >> i) & 1) && ((S >> j) & 1)) val[S] += a[i][j];
}
}
}
For(S,0,(1<<n)-1) {
dp[S] = val[S];
for (int j = S; j; j = S & (j - 1)) {
dp[S] = max(dp[S], dp[S^j] + dp[j]);
}
}
cout << dp[(1<<n)-1] << '\n';
return 0;
}
V#
W#
X#
贪心dp。
可以想到做 01 背包,但是转移拓扑序会出问题,以至于我们无法确定转移顺序。
考虑通过贪心确定转移顺序。直接按
然后按照顺序做背包即可。时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 1e3 + 10, M = 1e5 + 10;
struct Node {
int w, s, v;
} a[N];
int n, dp[M], ans;
bool cmp(Node x, Node y) {
return x.w + x.s < y.w + y.s;
}
signed main() {
cin >> n;
For(i,1,n) cin >> a[i].w >> a[i].s >> a[i].v;
sort(a + 1, a + n + 1, cmp);
dp[0] = 0;
For(i,1,n) {
FOR(j,a[i].s,0) {
dp[j + a[i].w] = max(dp[j + a[i].w], dp[j] + a[i].v);
}
}
For(i,0,M-1) ans = max(ans, dp[i]);
cout << ans << '\n';
return 0;
}
Y#
Z#
作者:Daniel-yao
出处:https://www.cnblogs.com/Daniel-yao/p/18449374
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效