codeforces dp例题学习

目录

C. Hamiltonian Wall

题意:

dp思路:

代码:

E. Negatives and Positives

题意:

dp思路:

代码:


C. Hamiltonian Wall

Problem - 1766C - Codeforces

题意:

给一个2*m的字符数组,能不能一笔把所有的B连起来

input

6

3

WBB

BBW

1

B

B

5

BWBWB

BBBBB

2

BW

WB

5

BBBBW

BWBBB

6

BWBBWB

BBBBBB

output

YES
YES
NO
NO
NO
YES

dp思路:

dp[ 1/2 ] [ j ]表示 第1/2行第 j 列能否作为画笔的终点

初始化:如果第一列的字符是B,从这个点开始,同时它是第1列的终点

一列一列往后扫,如果是W,连不到当前点,如果是B,则由前一列状态转移来

如果当前列两行都是B,由于一笔连成,画笔停在另外一行,即两行的状态交换

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define forn(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;

void solve(){
    int n;
    cin>>n;
    string s1,s2;
    cin>>s1>>s2;
    vector<vector<int> >dp(3,vector<int>(n));

    dp[1][0]=(s1[0]=='B');      //初始化
    dp[2][0]=(s2[0]=='B');

    for(int i=1;i<n;i++){

        if(s1[i]=='W')dp[1][i]=0;   //不连当前点
        if(s2[i]=='W')dp[2][i]=0;

        if(s1[i]=='B')dp[1][i]=dp[1][i-1];  //状态转移
        if(s2[i]=='B')dp[2][i]=dp[2][i-1];

        if(s1[i]=='B'&&s2[i]=='B')swap(dp[1][i],dp[2][i]);
            //画笔连住在这一列
    }
    cout<<((dp[1][n-1]||dp[2][n-1])?"YES":"NO")<<endl;
}

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

    int T=1;
    cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

E. Negatives and Positives

Problem - E - Codeforces

题意:

给一个数组,每次可以把相邻两项变为负数,求若干次操作后的最大数组元素之和

input

5

3

-1 -1 -1

5

1 5 -5 0 2

3

1 2 3

6

-1 10 9 8 7 6

2

-1 -1

output

1
13
6
39
2

dp思路:

dp [ 1/2 ] [ i ] 表示第 i 个元素 操作/不操作 后的最大前缀和

状态转移方程,dp [ 1 ] [ i ]  = max ( dp [ 1 ] [ i -1 ] , dp [ 2 ] [ i - 1 ] ) + a[ i ] 

dp [ 2 ] [ i ] = max ( dp [ 1 ] [ i-1 ] - 2*a[ i-1 ] , dp [ 2 ] [ i-1 ] + 2*a[ i-1 ] ) - a[ i ]  

代码:

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;

void solve(){
    int n;
    cin>>n;
    vector<ll>a(n+1);
    vector<vector<ll> >dp(3,vector<ll>(n+1));

    for(int i=1;i<=n;i++)cin>>a[i];

    if(n==1){
        cout<<a[1]<<endl;
        return;
    }

    dp[1][2]=a[1]+a[2];        //初始化
    dp[2][2]=-a[1]-a[2];

    for(int i=3;i<=n;i++){
        dp[1][i]=max(dp[1][i-1]+a[i],dp[2][i-1]+a[i]);      //不翻转直接加上
        dp[2][i]=max(dp[1][i-1]-2*a[i-1]-a[i],dp[2][i-1]-a[i]+2*a[i-1]);    //翻转的话前去前一个的二倍
    }

    cout<<max(dp[1][n],dp[2][n])<<endl;
}


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

    int T=1;
    cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Auroraaaaaaaaaaaaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值