CF1631E. Paint the Middle **

link
dp/贪心 2200

题意

给定 n n n 个元素,元素 i i i 具有值 a i a_i ai 和颜色 c i c_i ci,最初,对于所有 i i i c i = 0 c_i=0 ci=0。可以不限次数地进行以下操作:
选取三个元素 i , j , k ( 1 ≤ i < j < k ≤ n ) i,j,k(1\leq i<j<k\leq n) i,j,k1i<j<kn,其中 c i = c j = c k = 0 c_i=c_j=c_k=0 ci=cj=ck=0 a i = a k a_i=a_k ai=ak,令 c j c_j cj=1。
m a x Σ c i max \Sigma c_i maxΣci为多少?

思路

  1. 贪心
    显然对于每个数字,我们只需要考虑第一个和最后一个出现的位置,用 pos[i]表示数字 i i i 最后一次出现的位置。如果数字之间不影响,每次可以将第一个出现的位置和最后一个出现的位置之间的 c c c 均改为1。关键在于有重合部分的情况。对每个 i i i,用cover表示当前区间的右端点,r表示从1到 i i i a i a_i ai 的最右端点,若cover > i,则cnt++,表示这个数可以变为1。否则更新cover=r
void solve() {
    cin >> n;
    for(int i = 1; i <= n; i++) {
    	cin >> a[i];
    	pos[a[i]] = i;
    }
    int r = 0, cnt = 0, cover = 0;
    for(int i = 1; i <= n; i++) {
    	r = max(r, pos[a[i]]);
    	if(cover > i) cnt++;
    	else cover = r;
    }
    cout << cnt << endl;
}
  1. dp
    dp[i]表示前 i i i 个数中0的数量。每个数肯定都可以取0,故dp[i]=min(dp[i-1]+1, dp[i])cur表示右端点最大值,dp[cur]=min(dp[cur], dp[i] + 1)(因为cur对应的的左端点一定小于等于i所以可以把 i+1cur-1之间均变为1,也就是说可以做到只有cur处为0,故dp[cur]可以取dp[i]+1
void solve() {
    cin >> n;
    for(int i = 1; i <= n; i++) {
    	cin >> a[i];
    	pos[a[i]] = i;
    }
    memset(dp,0x3f,sizeof(dp));
    dp[0] = 0;
    int cur = pos[a[1]];
    for(int i = 1; i <= n; i++) {
    	dp[i] = min(dp[i-1] + 1, dp[i]);
    	cur = max(cur, pos[a[i]]);
    	dp[cur] = min(dp[i] + 1, dp[cur]);
    }
    cout << n - dp[n] << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值