DP(区间专题八)

14 篇文章 0 订阅
4 篇文章 0 订阅

题意: 题意还是很复杂的, 还是看题面理解的快些

>> [IOI1998]Polygon <<

Strategy:环链化 + 区间dp 其实这一题和石子合并挺像的

状态: d p [ l ] [ r ] → dp[l][r]\to dp[l][r]该区间内最大收益

目标: max ⁡ ( d p [ i ∈ [ 1 , n ] ] [ n + i − 1 ] ) \max(dp[i\in[1,n]][n + i - 1]) max(dp[i[1,n]][n+i1])

边界: d p [ i ] [ i ] = d p m i n [ i ] [ i ] = a [ i ] dp[i][i] = dpmin[i][i] = a[i] dp[i][i]=dpmin[i][i]=a[i]

合法判断: 所有情况都能转移

转移方程: 条件转移, 详情见代码

attention: 圆环是顺时针给出的, 对于每两个数的操作符号是后一个数所存储的操作;

双倍经验: 如何避免处理最优解的子结构包含负负得正的情况? 答曰: 维护每段区间的最大值和最小值, 按情况转移即可, 注意复杂转移要反复检查

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define _rep(i, a, b) for (ll i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (ll i = (a); i >= (b); --i)
#define _for(i, a, b) for (ll i = (a); i < (b); ++i)
#define _rof(i, a, b) for (ll i = (a); i > (b); --i)
#define ll long long
#define db double
#define oo 0x3f3f3f3f
#define eps 0.00001
#define all(x) x.begin(), x.end()
#define met(a, b) memset(a, b, sizeof(a))
#define id(x) ((x + 8))
#define bin(x) cerr << #x << " is " << bitset<15>(x) << endl
#define what_is(x) cerr << #x << " is " << x << endl
#define lowbit(x) x &(-x)
using namespace std;
const int maxn = 110;
int a[maxn], n, dp[maxn][maxn], dpmin[maxn][maxn];
char opera[maxn];
signed main()
{
	ios::sync_with_stdio(0);
	cin >> n;
	_rep(i, 1, n)
	{
		cin >> opera[i] >> a[i];
		a[i + n] = a[i], opera[i + n] = opera[i];
	}
	met(dpmin, oo), met(dp, -oo);
	_rep(i, 1, 2 * n) dp[i][i] = dpmin[i][i] = a[i];
	_rep(len, 2, n)
	{
		_rep(l, 1, 2 * n - len + 1)
		{
			int r = l + len - 1;
			_rep(k, l, r - 1)
			{
				if (opera[k + 1] == 't')
				{
					dp[l][r] = max(dp[l][k] + dp[k + 1][r], dp[l][r]);
					dpmin[l][r] = min(dpmin[l][k] + dpmin[k + 1][r], dpmin[l][r]);
				}
				else
				{
					dp[l][r] = max(dp[l][r], max(dp[l][k] * dp[k + 1][r], max(dpmin[l][k] * dpmin[k + 1][r], max(dp[l][k] * dpmin[k + 1][r], dpmin[l][k] * dp[k + 1][r]))));
					dpmin[l][r] = min(dpmin[l][r], min(dp[l][k] * dp[k + 1][r], min(dpmin[l][k] * dpmin[k + 1][r], min(dp[l][k] * dpmin[k + 1][r], dpmin[l][k] * dp[k + 1][r]))));
				}
			}
		}
	}
	int ans = 0;
	_rep(i, 1, n){
		ans = max(ans, dp[i][i + n - 1]);
	}
	cout << ans << endl;

	_rep(i, 1, n){
		if(ans == dp[i][i + n - 1]){
			cout << i << " ";
		}
	}
	
	
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值