动态规划板子合集(有用的)

二进制分组优化多重背包

index = 0;
for (int i = 1; i <= m; i++) {
  int c = 1, p, h, k;
  cin >> p >> h >> k;
  while (k > c) {
    k -= c;
    list[++index].w = c * p;
    list[index].v = c * h;
    c *= 2;
  }
  list[++index].w = p * k;
  list[index].v = h * k;
}

单调队列优化多重背包

#include <array>
#include <deque>
#include <iostream>

constexpr int MAXV = 4e4 + 10;
constexpr int MAXN = 1e2 + 10;

using namespace std;

int n, W, last = 0, now = 1;
array<int, MAXN> v, w, k;
array<array<int, MAXV>, 2> f;
deque<int> q;

int main() {
  ios::sync_with_stdio(false);
  cin >> n >> W;
  for (int i = 1; i <= n; i++) {
    cin >> v[i] >> w[i] >> k[i];
  }
  for (int i = 1; i <= n; i++) {
    for (int y = 0; y < w[i]; y++) {
      // 清空队列
      deque<int>().swap(q);
      for (int x = 0; x * w[i] + y <= W; x++) {
        // 弹出不在范围的元素
        while (!q.empty() && q.front() < x - k[i]) {
          q.pop_front();
        }
        // 保证队列单调
        while (!q.empty() && f[last][q.back() * w[i] + y] - q.back() * v[i] <
                                 f[last][x * w[i] + y] - x * v[i]) {
          q.pop_back();
        }
        q.push_back(x);
        f[now][x * w[i] + y] =
            f[last][q.front() * w[i] + y] - q.front() * v[i] + x * v[i];
      }
    }
    swap(last, now);
  }
  cout << f[last][W] << endl;
  return 0;
}

数位dp

#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;

ull f[20][10],power[20];
void init() {
	power[0]=1;
	for(int i=1;i<=19;i++) power[i]=power[i-1]*10;
	for(int i=0;i<=9;i++) f[1][i]=1;
	for(int i=2;i<=19;i++)
		for(int j=0;j<=9;j++)
			for(int k=0;k<=9;k++)
				if(abs(j-k)>=2)
					f[i][j]+=f[i-1][k];
	return ;
}
ull solve(ull x) {
	int w=0,y,pre;
	ull ans=0;
	while(power[w]<=x) w++;
	for(int i=1;i<w;i++)
		for(int j=1;j<=9;j++)
			ans+=f[i][j];
	y=x/power[w-1];
	for(int j=1;j<y;j++) ans+=f[w][j];
	pre=y,x%=power[w-1];
	for(int i=w-1;i>=1;i--) {
		y=x/power[i-1];
		for(int j=0;j<y;j++)
			if(abs(j-pre)>=2)
				ans+=f[i][j];
		if(abs(pre-y)<2) break;
		pre=y,x%=power[i-1];
	}
	return ans;
}

int main() {
	ull a,b;
	cin>>a>>b;
	init();
	cout<<solve(b+1)-solve(a)<<endl;
	return 0;
}

斜率优化(玩具装箱)

#include<bits/stdc++.h>
using namespace std;

#define db double
#define int long long
const int maxn = 1e6+10;

int n,L,v[maxn];
int f[maxn],sum[maxn];
int q[maxn],hd,tl;

inline int read(){
	int x = 0,f = 0;
	char c = getchar();
	while(!isdigit(c))
		f|=(c=='-'),c = getchar();
	while(isdigit(c))
		x = x*10+c-'0',c = getchar();
	if(f)x = -x;
	return x;
}

db a(int x){
	return sum[x]+x;
}

db b(int x){
	return sum[x]+x+L+1;
}

db X(int x){
	return a(x);
}

db Y(int x){
	return f[x]+b(x)*b(x);
}

db slope(int x,int y){
	return (Y(y) - Y(x))/(X(y) - X(x));
}

signed main(){
	#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
	#endif
	n = read(),L = read();
	for(int i=1;i<=n;i++){
		int x = read();
		sum[i] = sum[i-1]+x;
	}
	hd = tl = 1;
	for(int i=1;i<=n;i++){
		while(hd<tl&&slope(q[hd],q[hd+1])<2*a(i))
			hd++;
		f[i] = f[q[hd]]+(a(i) - b(q[hd]))*(a(i) - b(q[hd]));
		while(hd<tl&&slope(q[tl-1],q[tl])>slope(q[tl-1],i))
			tl--;
		q[++tl] = i;
	}
	printf("%lld\n",f[n]);
	return 0;
}

二分队列四边形不等式(诗人小G)

#include <bits/stdc++.h>
#define ll long double

using namespace std;

const int maxn = 1e6 + 10;
int T;
int p, n, pr[maxn], nxt[maxn], h, t;
ll a[maxn], s[maxn], le, f[maxn], q[maxn], r[maxn];
char c[maxn][40];

ll qpow(ll a, int b) {
    ll res = 1;
    while (b) {
        if (b & 1)
            res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}

ll calc(int i, int j) {
    return (f[j] + qpow(abs(s[i] - s[j] - 1 - le), p));
}

int bound(int x, int y) {
    int l = x, r = n + 1;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (calc(mid, x) >= calc(mid, y))
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    scanf("%d", &T);
    while (T--) {
        scanf("%d%Lf%d", &n, &le, &p);
        memset(f, 0x3f, sizeof(f));
        memset(pr, 0, sizeof(pr));
        memset(nxt, 0, sizeof(nxt));
        for (int i = 1; i <= n; ++i) {
            scanf("%s", c[i]);
            a[i] = (ll)strlen(c[i]) + 1;
            s[i] = s[i - 1] + a[i];
        }
        q[h = t = 1] = 0, r[h = t = 1] = n;
        f[0] = 0;
        for (int i = 1; i <= n; ++i) {
            while (h < t && r[h] < i)
                ++h;
            f[i] = calc(i, q[h]), pr[i] = q[h];
            while (h < t && r[t - 1] >= bound(q[t], i))
                --t;
            r[t] = bound(q[t], i) - 1, q[++t] = i;
        }
        if (f[n] > 1e18) {
            puts("Too hard to arrange");
        }
        else {
            printf("%0.Lf\n", f[n]);
            int x = n;
            while (pr[x]) {
                nxt[pr[x]] = x;
                x = pr[x];
            }
            nxt[0] = x;
            x = 0;
            while (nxt[x]) {
                for (int i = x + 1; i < nxt[x]; ++i) {
                    printf("%s ", c[i]);
                }
                printf("%s\n", c[nxt[x]]);
                x = nxt[x];
            }
        }
        puts("--------------------");
    }
    return 0;
}

分治决策单调性(魔法商店)

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int maxn = 2e6 + 10;

namespace IO {
void openfile() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
}

inline int read() {
    int x = 0, f = 0;
    char c = getchar();
    while (!isdigit(c))
        f |= c == '-', c = getchar();
    while (isdigit(c))
        x = x * 10 + c - '0', c = getchar();
    if (f)
        x = -x;
    return x;
}
}  // namespace IO
using namespace IO;

int n, m, k;
int sum[10][maxn];
int c[maxn], v[maxn], sta[10][maxn], top[maxn];
int f[10][maxn], now[maxn], num;

void dp(int pos, int l, int r, int x, int y) {
    if (l > r)
        return;
    int mid = (l + r) >> 1, p = mid;
    for (int i = max(x, mid - top[pos]); i <= min(mid, y); i++)
        if (f[pos - 1][now[i]] + sum[pos][mid - i] >= f[pos - 1][now[p]] + sum[pos][mid - p])
            p = i;
    //这个位置一定要是>=因为p如果是mid可能会大于等于y,这样右区间就没有决策区间了
    f[pos][now[mid]] = f[pos - 1][now[p]] + sum[pos][mid - p];
    dp(pos, l, mid - 1, x, p), dp(pos, mid + 1, r, p, y);
}

bool cmp(int x, int y) {
    return x > y;
}

signed main() {
    openfile();
    n = read(), m = read(), k = read();
    for (int i = 1; i <= n; i++) {
        c[i] = read(), v[i] = read();
        sta[c[i]][++top[c[i]]] = v[i];
    }
    for (int i = 1; i <= 7; i++)
        sort(sta[i] + 1, sta[i] + 1 + top[i], cmp);
    for (int i = 1; i <= 7; i++)
        for (int j = 1; j <= top[i]; j++)
            sum[i][j] = sum[i][j - 1] + sta[i][j];
    memset(f, -0x7f, sizeof(f));
    f[0][0] = 0;
    for (int i = 1; i <= 7; i++) {
        for (int j = 0; j < min(m + 1, i); j++) {
            for (int k = j; k <= m; k += i)
                now[++num] = k;
            dp(i, 1, num, 1, num);
            for (int k = 1; k <= num; k++)
                now[k] = 0;
            num = 0;
        }
    }
    // for (int i = 1; i <= 7; i++) {
    //     for (int j = 0; j <= m; j++)
    //         cout << f[i][j] << ' ';
    //     cout << endl;
    // }
    int ans = 0;
    for (int i = 1; i <= m; i++) {
        ans = max(ans, f[7][i]);
        printf("%lld\n", ans);
    }
    cerr << 1.0 * clock() / CLOCKS_PER_SEC << '\n';
    return 0;
}

slope trick(P4331 [BalticOI 2004] Sequence 数字序列)

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define pii pair<int, int>
#define mp make_pair
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;

namespace IO {
void openfile() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
}

int mul(int x, int y) {
    return 1ll * x * y % mod;
}

int add(int x, int y) {
    x += y;
    if (x >= mod)
        x -= mod;
    return x;
}

int sub(int x, int y) {
    return add(x, mod - y);
}

inline int read() {
    int x = 0, f = 0;
    char c = getchar();
    while (!isdigit(c))
        f |= c == '-', c = getchar();
    while (isdigit(c))
        x = x * 10 + c - '0', c = getchar();
    if (f)
        x = -x;
    return x;
}
}  // namespace IO
using namespace IO;

int n, a[maxn];
int top, ans;
int b[maxn], ls[maxn], rs[maxn], tot, dis[maxn];

struct node {
    int rt, l, r, siz, val;
} sta[maxn];

int merge(int x, int y) {
    if (!x || !y)
        return x + y;
    if (a[x] < a[y])
        swap(x, y);
    rs[x] = merge(rs[x], y);
    if (dis[ls[x]] < dis[rs[x]])
        swap(ls[x], rs[x]);
    dis[x] = dis[rs[x]] + 1;
    return x;
}

int del(int x) {
    return merge(ls[x], rs[x]);
}

signed main() {
    openfile();
    dis[0] = -1;
    n = read();
    for (int i = 1; i <= n; i++)
        a[i] = read() - i;
    for (int i = 1; i <= n; i++) {
        sta[++top] = {i, i, i, 1, a[i]};
        while (top != 1 && sta[top - 1].val > sta[top].val) {
            top--;
            sta[top].rt = merge(sta[top].rt, sta[top + 1].rt);
            sta[top].siz += sta[top + 1].siz;
            sta[top].r = sta[top + 1].r;
            while (sta[top].siz > (sta[top].r - sta[top].l + 2) / 2)
                sta[top].siz--, sta[top].rt = del(sta[top].rt);
            sta[top].val = a[sta[top].rt];
        }
    }
    int cnt = 1;
    for (int i = 1; i <= n; i++) {
        if (sta[cnt].r < i)
            ++cnt;
        ans += abs(sta[cnt].val - a[i]);
    }
    printf("%lld\n", ans);
    cnt = 1;
    for (int i = 1; i <= n; i++) {
        if (sta[cnt].r < i)
            ++cnt;
        printf("%lld ", sta[cnt].val + i);
    }
    puts("");
    cerr << 1.0 * clock() / CLOCKS_PER_SEC << '\n';
    return 0;
}
posted @ 2025-09-05 23:26  Johnsonloy  阅读(16)  评论(0)    收藏  举报