D2. Zero-One(区间dp -❌- 线性dp -✔-)

  • https://codeforces.com/contest/1733/problem/D2
  1. 找出对应不同的位置数组dif
  2. 对于两个不同的位置$dif_{i-1}$和$dif_i$,有四种可行的操作
    1. $dif_{i-1} + 1 = dif_i$,用一次x操作
    2. $dif_{i-1} + 1 = dif_i$,用l两次y操作
    3. $dif_{i-1} + 1 ≠ dif_i$,用$dif_i - dif_{i-1} $次x操作(从左到右一个一个走)
    4. $dif_{i-1} + 1 ≠ dif_i$,用一次y操作
  3. 上面的操作可以通过区间dp来实现
    状态表示:$f[l][r]$表示{l,r}区间内所有匹配完成的最小cost
    状态转移:类似区间dp的转移方式,len小于等于2时为0,初始全为inf
  4. 还有一些其他的特判
    比如dif的个数为奇数,那么显然无解
  5. 这里代码用了记忆化搜索
#include<bits/stdc++.h>
#define debug1(a) cout<<#a<<'='<< a << endl;
#define debug2(a,b) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<endl;
#define debug3(a,b,c) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<endl;
#define debug4(a,b,c,d) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<"  "<<#d<<" = "<<d<<endl;
#define debug5(a,b,c,d,e) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<"  "<<#d<<" = "<<d<<"  "<<#e<<" = "<<e<<endl;
#define debug0(x) cout << "debug0: " << x << endl
#define fr(t, i, n)for (int i = t; i < n; i++)
#define fi first
#define se second
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;

//#pragma GCC optimize(3,"Ofast","inline")
//#pragma GCC optimize(2)
const int N = 5010;
LL dif[N],ed;
LL n,x,y;
LL f[N][N];

LL get(LL l,LL r)
{
    if(l+1 == r)return min(x,2*y);
    else return min(x*(r-l),y);
}

LL dfs(LL l,LL r)
{
    if(l > r)return 0;
    if(f[l][r] != -1)return f[l][r];
    LL res = 1e18;
    res = min(res,dfs(l,r-2) + get(dif[r-1],dif[r]));
    res = min(res,dfs(l+1,r-1) + get(dif[l],dif[r]));
    res = min(res,dfs(l+2,r) + get(dif[l],dif[l+1]));
    return f[l][r] = res;
}

void solve(){
    cin >> n >> x >> y;
    string s1,s2;cin >> s1 >> s2;
    ed = 0;
    for(int i = 0;i < n;i ++)for(int j = 0;j < n;j ++)f[i][j] = -1;
    for(int i = 0;i < n;i ++)if(s1[i] != s2[i])dif[ed++] = i;
    if(ed % 2)
    {
        cout << -1 << endl;
        return ;
    }
    if(ed == 2)
    {
        cout << get(dif[0],dif[1]) << endl;
        return ;
    }
    if(ed == 0)
    {
        cout << 0 << endl;
        return ;
    }
    if(y <= x){cout << ed/2LL*y << endl;return;}

    cout << dfs(0,ed-1) << endl;
}

int main()
{
    /*
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    */

    int T = 1;cin >> T;
    while(T--){
        solve();
    }
    return 0;
}
  1. 在上面的思路O($n^2$),我们可以优化一下,直接用线性dp完成,实现O($n$)
  2. 学习自CF1733D2 Zero-One (Hard Version) 题解 - 灵茶山艾府 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define debug1(a) cout<<#a<<'='<< a << endl;
#define debug2(a,b) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<endl;
#define debug3(a,b,c) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<endl;
#define debug4(a,b,c,d) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<"  "<<#d<<" = "<<d<<endl;
#define debug5(a,b,c,d,e) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<"  "<<#d<<" = "<<d<<"  "<<#e<<" = "<<e<<endl;
#define fr(t, i, n)for (long long i = t; i < n; i++)
#define endl "\n"
#define fi first
#define se second
#define int long long
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;

//#pragma GCC optimize(3,"Ofast","inline")
//#pragma GCC optimize(2)

const int N = 5010;
LL dif[N],ed;
LL n,x,y;
LL f[N];
 
LL get(LL l,LL r)
{
    if(l+1 == r)return min(x,2*y);
    else return min(x*(r-l),y);
}
 
void solve(){
    cin >> n >> x >> y;
    string s1,s2;cin >> s1 >> s2;
    ed = 0;
    for(int i = 0;i < n;i ++)if(s1[i] != s2[i])dif[ed++] = i;
    if(ed % 2)
    {
        cout << -1 << endl;
        return ;
    }
    if(ed == 2)
    {
        cout << get(dif[0],dif[1]) << endl;
        return ;
    }
    if(ed == 0)
    {
        cout << 0 << endl;
        return ;
    }
    if(y <= x)cout << ed/2LL*y << endl;
    else 
    {
        fill(f,f+ed,1e15);
        f[0] = y;
        f[1] = min(f[0] + y,(dif[1] - dif[0])*x*2);
        for(int i = 2;i < ed;i ++)
        {
            f[i] = min(f[i-1] + y,f[i]);
            f[i] = min(f[i-2] + (dif[i] - dif[i-1])*x*2,f[i]);
        }
        cout << f[ed-1]/2 << endl;
    }
}

signed main()
{
    /*
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    */
    int T = 1;cin >> T;
    
    while(T--){
        //puts(solve()?"YES":"NO");
        solve();
    }
    return 0;
}
/*

*/

 

posted @ 2023-01-04 14:26  俄罗斯刺沙蓬  阅读(34)  评论(0编辑  收藏  举报
返回顶端