Codeforces 1144G(dp)

据说这题是种dp的套路?然后被我国红名神仙(南大Roundgod)贪心了,不过思路上非常相近了,故而可贪吧。

设的dp[i][0]是:如果把第i个数放在上升序列里了,那么下降序列结尾的那个最大是多少;同理,dp[i][1]是:如果把第i个数放在下降序列里了,那么上升序列结尾的那个最大是多少。

个人yy,这样设的巧妙之处大概就是我们想转移第i个时,需要比较一下大小才能看第i个能不能插入某个序列,而你发现这个dp明明含义是把i放上升里了,记录的却是下降的结尾——这就使得我们拿到i+1个时,想放上升时就跟a[i]比,想放下降时就跟dp[i][0]比,这就可以转移了,其他几种情况同理。

尽量让下降序列的结尾更大,上升序列的结尾更小,才会“家有余粮,心里不慌”,对后面的数列更具包容性。这大概也是可以贪心的哲学道理吧(大雾

 

 1 const int maxn = 2e5 + 5;
 2 int n, a[maxn];
 3 int pre[maxn][2];
 4 
 5 void print(int i, int pos) {
 6     if (i) {
 7         print(i - 1, pre[i][pos]);
 8     }
 9     printf("%d ", pos);
10 }
11 
12 int main() {
13     read(n);
14     rep(i, 0, n - 1)    read(a[i]);
15 
16     vector<vector<int>>dp(n, vector<int>({-inf, inf}));
17 
18     dp[0][0] = inf, dp[0][1] = -inf;
19     rep(i, 1, n - 1) {
20         //add to increase
21         if (a[i] > a[i - 1] && dp[i][0] < dp[i - 1][0]) {
22             dp[i][0] = dp[i - 1][0];
23             pre[i][0] = 0;
24         }
25         if (a[i] > dp[i - 1][1] && dp[i][0] < a[i - 1]) {
26             dp[i][0] = a[i - 1];
27             pre[i][0] = 1;
28         }
29         //add to decrease
30         if (a[i] < a[i - 1] && dp[i][1] > dp[i - 1][1]) {
31             dp[i][1] = dp[i - 1][1];
32             pre[i][1] = 1;
33         }
34         if (a[i] < dp[i - 1][0] && dp[i][1] > a[i - 1]) {
35             dp[i][1] = a[i - 1];
36             pre[i][1] = 0;
37         }
38     }
39 
40     int pos = -1;
41     if (dp[n - 1][0] != -inf)    pos = 0;
42     if (dp[n - 1][1] != inf)    pos = 1;
43 
44     if (pos < 0)    puts("NO");
45     else {
46         puts("YES");
47         print(n - 1, pos);
48     }
49 
50     return 0;
51 }

 

转载于:https://www.cnblogs.com/AlphaWA/p/10644770.html

区间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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值