Codeforces 2096C Wonderful City 题解 [ 绿 ] [ 线性 DP ]

Wonderful City:整场卡在这道题上了,我糖丸了。

首先注意到每行每列只能操作一次,并且改变行的时候只会改变纵向相等的数,改变行的时候只会改变横向相等的数。所以我们可以对行和列分别操作。同时这个结论也可以通过差分理解。

因为对行和列操作做法是一样的,这里以行为例。

注意到如果某一行和前一行相邻的数存在小 \(1\) 的,就不能只操作这一行;如果某一行和前一行相邻的数存在大 \(1\) 的,就不能只操作前一行;如果某一行和前一行相邻的数存在相等的,就不能两行同时操作。

所以我们可以发现每一行有操不操作的这个 \(0/1\) 状态,于是设计 \(dp_{i,0/1}\) 表示考虑前 \(i\) 行,第 \(i\) 行不操作 / 操作的最小操作次数,规避掉前文所说的不合法情况转移即可。

时间复杂度 \(O(n^2)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=1005;
int n;
ll h[N][N],a[N],b[N],dp[N][2],ans=0;

void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>h[i][j];
        }
    }
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    memset(dp,0x3f,sizeof(dp));
    dp[1][0]=0;
    ans=0;
    dp[1][1]=a[1];
    for(int i=2;i<=n;i++)
    {
        int x=0,y=0,z=0;
        for(int j=1;j<=n;j++)
        {
            int cz=h[i][j]-h[i-1][j];
            if(cz==1)x=1;
            if(cz==0)y=1;
            if(cz==-1)z=1;
        }
        if(x==0)dp[i][0]=min(dp[i][0],dp[i-1][1]);
        if(y==0)dp[i][0]=min(dp[i][0],dp[i-1][0]);
        if(y==0)dp[i][1]=min(dp[i][1],dp[i-1][1]+a[i]);
        if(z==0)dp[i][1]=min(dp[i][1],dp[i-1][0]+a[i]);
    }
    ans+=min(dp[n][0],dp[n][1]);

    memset(dp,0x3f,sizeof(dp));
    dp[1][0]=0;
    dp[1][1]=b[1];
    for(int i=2;i<=n;i++)
    {
        int x=0,y=0,z=0;
        for(int j=1;j<=n;j++)
        {
            int cz=h[j][i]-h[j][i-1];
            if(cz==1)x=1;
            if(cz==0)y=1;
            if(cz==-1)z=1;
        }
        if(x==0)dp[i][0]=min(dp[i][0],dp[i-1][1]);
        if(y==0)dp[i][0]=min(dp[i][0],dp[i-1][0]);
        if(y==0)dp[i][1]=min(dp[i][1],dp[i-1][1]+b[i]);
        if(z==0)dp[i][1]=min(dp[i][1],dp[i-1][0]+b[i]);
    }
    ans+=min(dp[n][0],dp[n][1]);
    if(ans>=0x3f3f3f3f3f3f3f3f/2)cout<<-1<<'\n';
    else cout<<ans<<'\n';
}
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    while(t--)solve();
    return 0;
}
posted @ 2025-05-03 11:27  KS_Fszha  阅读(21)  评论(0)    收藏  举报
OSZAR »