一些转移细节还不太清楚的线性dp

发布时间 2023-10-06 22:32:35作者: Sakana~

D. Round Subset

老早写过了,但是边界考虑不太清楚
https://codeforces.com/problemset/problem/837/D

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

using namespace std;
const int N = 205, M = 30 * 200;
int n, k, ans, t2[N], t5[N], f[2][N][M]; //f[i][j]: 选了i个, 5的值为j的最大2的个数

int main () {
    scanf ("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        ll x;
        scanf ("%lld", &x);
        while (x && x % 2 == 0)  t2[i]++, x /= 2;
        while (x && x % 5 == 0)  t5[i]++, x /= 5;
        //cout << t2[i] << ' ' << t5[i] << endl;
    }
    memset (f, -1, sizeof f);
    f[0][0][0] = f[1][0][0] = 0;
    for (int ii = 1; ii <= n; ii++) {
        int t = ii & 1, tt = t ^ 1;
        for (int i = 0; i <= min (ii, k); i++) { //i之前选了多少
            for (int j = 0; j <= 30 * i; j++) { //之前有多少个5
                if (!i || j < t5[ii] || f[t][i - 1][j - t5[ii]] == -1)   continue;
                f[tt][i][j] = max (f[tt][i][j], f[t][i - 1][j - t5[ii]] + t2[ii]);
            }
        }
        //记得滚过来
        for (int i = 0; i <= min (ii, k); i++) { 
            for (int j = 0; j <= 30 * i; j++) {
                f[t][i][j] = f[tt][i][j];
            }
        }
    }
    for (int i = 0; i <= 30 * n; i++)    ans = max (ans, min(f[n & 1][k][i], i));
    cout << ans << endl;
    //cout << log (1e18) / log (5);
}