洛谷dp记录
线性dp,分开处理数据
https://www.luogu.com.cn/problem/P1095
#include <bits/stdc++.h>
using namespace std;
const int N = 300010;
int m, s, t, dp[N], dpt[N]; //分开计算跑步还是等待
int main()
{
cin >> m >> s >> t;
for (int i = 1; i <= t; i++)
{
if (m >= 10)
{
m -= 10, dp[i] = dp[i - 1] + 60;
dpt[i] = max(dpt[i - 1] + 17, dp[i]);
} //能闪现就闪现
else
{
m += 4;
dp[i] = dp[i - 1];
dpt[i] = dpt[i - 1] + 17;
} //不能闪现就都记录下来
}
for (int i = 1; i <= t; i++)
{
if (dpt[i] >= s)
{
cout << "Yes" << endl
<< i << endl;
return 0;
}
}
cout << "No" << endl
<< dpt[t] << endl;
return 0;
}
背包dp,注意限制条件,注意初始化啊…
https://www.luogu.com.cn/problem/P1077
#include <bits/stdc++.h>
using namespace std;
int main()
{
const int N = 300, mod = 1000007;
int n, m, a[N], f[N][N];
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
f[0][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
for (int k = 0; k <= a[i] && k <= j; k++)
{
f[i][j] += f[i - 1][j - k];
f[i][j] %= mod;
}
}
}
cout << f[n][m] % mod << endl;
return 0;
}
二进制分解,第一次遇到这样转化多重背包到01背包
https://www.luogu.com.cn/problem/P1833
#include <cstdio>
#include <algorithm>
using namespace std;
int nx, ny, ex, ey, n, f[1010];
int v[10005], w[10005], a[10005];
int tp, co[1000005], vi[1000005]; //尽可能开大,不要把空间开爆了
inline void pre()
{
for (int i = 1; i <= n; i++)
{
int t = 1;
while (a[i])//分解过程好理解,代码这样写比较简单
{
co[++tp] = t * v[i];
vi[tp] = t * w[i];
a[i] -= t;
t *= 2;
if (a[i] < t)
{ //如果剩下的不能再拆,就直接放在一起
co[++tp] = v[i] * a[i];
vi[tp] = w[i] * a[i];
break;
}
}
}
}
int main()
{
scanf("%d:%d%d:%d%d", &nx, &ny, &ex, &ey, &n);
int t = (ex * 60 + ey) - (nx * 60 + ny);
for (int i = 1; i <= n; i++)
{
scanf("%d%d%d", &v[i], &w[i], &a[i]);
if (!a[i])
a[i] = 999999;
}
pre(); //二进制拆分
for (int i = 1; i <= tp; i++)
{ //考虑每个拆出来的物品
for (int j = t; j >= co[i]; j--) //01背包板子
f[j] = max(f[j], f[j - co[i]] + vi[i]);
}
printf("%d", f[t]);
return 0;
}
这个线性dp就很迷,第一次见…
啊啊啊我到底为啥都是第一次见啊
https://www.luogu.com.cn/problem/P3842
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 20010
#define int long long
using namespace std;
int n;
int dp[MAXN][2],dis[2][2],l[MAXN],r[MAXN];
//dis[0][0] left->left
//dis[0][1] left->right
//dis[1][0] right->left
//dis[1][1] right->right
int ans;
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&l[i],&r[i]);
l[0]=r[0]=1;
l[n+1]=r[n+1]=n;
for(int i=1;i<=n+1;i++)
{
if(l[i-1]<l[i])
dis[0][0]=r[i]-l[i-1]+r[i]-l[i],dis[0][1]=r[i]-l[i-1];
else if(l[i-1]>r[i])
dis[0][0]=l[i-1]-l[i],dis[0][1]=r[i]-l[i]+l[i-1]-l[i];
else
dis[0][0]=2*r[i]-l[i-1]-l[i],dis[0][1]=l[i-1]-l[i]+r[i]-l[i];
//the last position of the point is on the left
if(r[i-1]<l[i])
dis[1][0]=r[i]-r[i-1]+r[i]-l[i],dis[1][1]=r[i]-r[i-1];
else if(r[i-1]>r[i])
dis[1][0]=r[i-1]-l[i],dis[1][1]=r[i-1]-l[i]+r[i]-l[i];
else
dis[1][0]=r[i]-r[i-1]+r[i]-l[i],dis[1][1]=r[i-1]-l[i]+r[i]-l[i];
//the last position of the point is on the right
dp[i][0]=min(dp[i-1][0]+1+dis[0][0],dp[i-1][1]+1+dis[1][0]);
dp[i][1]=min(dp[i-1][0]+1+dis[0][1],dp[i-1][1]+1+dis[1][1]);
}
printf("%lld\n",min(dp[n+1][0],dp[n+1][1])-2);
return 0;
}
我巨菜啊啊啊啊吐血,石子归并在直线上刚会写,搞个圆形咋写啊
看了好多篇题解,发现都好难,按照我的理解wa了一个晚上…
后来才发现dp数组没初始化啊啊啊啊啊
#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
int n, p[N], dp[N][N], dpt[N][N];
int sum[N];
const int inf = 0x3f3f3f3f;
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
cin >> p[i];
int imax = 0, imin = 0x3f3f3f3f;
for (int st = 0; st < n; st++)
{
memset(sum, 0, sizeof(sum));
for (int t = st; t < st + n; t++)
{
sum[t - st + 1] = sum[t - st] + p[t % n];
// cout << sum[t - st + 1] << "\t";
} //更新前缀和
// cout << endl;
memset(dp, 0, sizeof(dp));
memset(dpt, inf, sizeof(dpt));
for (int i = 1; i <= n; i++)
dpt[i][i] = 0;
for (int i = n - 1; i >= 1; i--)
for (int j = i + 1; j <= n; j++)
for (int k = i; k <= j - 1; k++)
{
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]);
dpt[i][j] = min(dpt[i][j], dpt[i][k] + dpt[k + 1][j] + sum[j] - sum[i - 1]);
}
//cout << dp[1][n] << "\t" << dpt[1][n] << endl;
if (imax < dp[1][n])
imax = dp[1][n];
if (imin > dpt[1][n])
imin = dpt[1][n];
}
cout << imin << endl
<< imax << endl;
return 0;
}