第十八届浙大城市学院程序设计竞赛(同步赛)K

第十八届浙大城市学院程序设计竞赛(同步赛)K

大意

略。。

思路

什么叫王中王啊。。要是比赛时调出来,直接从100+蹦到20整(

首先我们按行观察矩阵,不难发现每行选择的个数一定是非递降的才能满足题意,也就是每行不能选的比上一行多。

所以, 先设设 (dp[i][j][k]) 表示第 (i) 行 ,本行选了 (j) 个方块,且总共选了 (k) 个方块时的最大值。

因为我们在当前行,如果要选 (r) 个,只需要上一行选择个数大于等于 (r) 即可。

如果直接枚举上一行选择几个,即枚举 (rleq j)(j) 的值显然复杂度过大,所以我们对 (j) 这一维做一下后缀优化,即将 (j) 的定义改为:本行选了大于等于 (j) 个方块。

这样理论复杂度是 (Theta(n*m*min(1000,n*m)))

因为空间会炸(

所以将 (i) 的一维要换成滚动数组。

代码

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)

const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;

ll n, m, kk;
ll d[2][1001][301];
// 第i行总共选了j个方格且第i行选择的方格数大于等于k的最大值
ll sum[301][301];
ll ans;

int main() {
    cin >> n >> m >> kk;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++) {
            cin >> sum[i][j];
            sum[i][j] += sum[i][j-1];
        }
    for(int i=1, st = 1; i<=n; i++, st ^= 1) {
        memset(d[st], -1, sizeof d[st]);
        for(int j=kk; j>=0; j--) {
            for(int k=m; k>=1; k--) {
                if(k != m) d[st][j][k] = max(d[st][j][k], d[st][j][k+1]);
                if(j>=k)if(d[st^1][j-k][k] >= 0) {
                    d[st][j][k] = max(d[st][j][k], d[st^1][j-k][k] + sum[i][k]);
                    ans = max(ans, d[st][j][k]);
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/ullio/p/14596208.html