P3558 [POI2013]BAJ-Bytecomputer(线性dp)

传送门

题目翻译:

给一个只包含-1,0,1的数列,每次操作可以让a[i]+=a[i-1],求最少操作次数使得序列单调不降

数据范围为N<=10^6

思路:线性dp,定义f[i][3],1<=i<=n,当前位置i取-1,0,1,数列1-i满足不下降的最小操作次数

直接看代码注释吧,主要懒

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1001000;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1000007;
int n;
int f[maxn][3], a[maxn];
int main() {
    //freopen("test.txt", "r", stdin);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        a[i]++;
    }
    memset(f, 0x3f, sizeof(f));
    f[1][a[1]] = 0;
    for (int i = 2; i <= n; i++) {
        if (a[i] == 0) {//当前位置最初为-1
            f[i][0] = f[i - 1][0];//当前位置选-1,前一位置只能选-1,且不需要对当前数字进行修改
            //如果初始为-1,而要改成0/1,则要从前一位置为1的情况转移过来
            if (a[i - 1] == 2) {//如果前一位置最初就为1,则一开始就能进行操作,所以最终前一位置可以取-1,0,1都可以
                f[i][1] = min(f[i - 1][1], f[i - 1][0]) + 1;//最开始就操作一次,变为0, 前一位置可以为-1,0
                f[i][2] = min(min(f[i - 1][0], f[i - 1][1]), f[i - 1][2]) + 2;//一开始就操作两次,变为1, 前一位置可以为-1,0,1
            }
            else {//前一位置不为1
                f[i][1] = inf;//前一位置不为1,而当前位置还要为0是不可能的,因为这种情况下当前位置数值增大,只能前一位置改变为1,再修改为0,但是10不满足不下降
                f[i][2] = f[i - 1][2] + 2;//只能把前一位置先修改为1,再进行两次增加操作
            }
            //cout << i << " " << f[i][0] << " " << f[i][1] << " " << f[i][2] << endl;
        }
        else if (a[i] == 1) {
            f[i][0] = f[i - 1][0] + 1;//为0转变为-1,前一位置只能取-1,而且需要操作一次
            f[i][1] = min(f[i - 1][1], f[i - 1][0]);//前一位置可以为-1/0
            if (a[i - 1] == 2) {//和上一操作同理,看前一位置的数最开始是不是1,是1就可以一开始就直接对当前位置进行+1操作变为1
                //此时前一位置就能取-1,0,1
                f[i][2] = min(min(f[i - 1][2], f[i - 1][0]), f[i - 1][1]) + 1;
            }
            else {//不然就只能先把前一位置变为1,再进行+1操作,此时前一位置就只能取1
                f[i][2] = f[i - 1][2] + 1;
            }
            //cout << i << " " << f[i][0] << " " << f[i][1] << " " << f[i][2] << endl;
        }
        else {//下面同理了
            f[i][0] = f[i - 1][0] + 2;
            if (a[i - 1] == 0) {
                f[i][1] = min(f[i - 1][0], f[i - 1][1]) + 1;
            }
            else {
                f[i][1] = f[i - 1][0] + 1;
            }
            f[i][2] = min(min(f[i - 1][2], f[i - 1][0]), f[i - 1][1]);
            //cout << i << " " << f[i][0] << " " << f[i][1] << " " << f[i][2] << endl;
        }
    }
    int ans = min(f[n][2], min(f[n][0], f[n][1]));
    if (ans >= inf) {//无解
        printf("BRAK\n");
    }
    else {
        cout << ans << endl;
    }
    return 0;
}

 

上一篇:弗洛伊德(Floyd)算法


下一篇:数学建模(二)—— 蔬菜供应方案设计