Codeforces 1509C The Sports Festival 区间dp & Codeforces 1509D Binary Literature 抽屉原理,构造

4 篇文章 0 订阅

C

题意

给 一 个 序 列 , 令 d i = max ⁡ ( a 1 . . . a i ) − min ⁡ ( a 1 . . . a i ) , 求 min ⁡ ∑ i = 1 n d i 给一个序列,令d_i=\max(a_1...a_i)-\min(a_1...a_i),求\min \sum_{i=1}^n{} d_i ,di=max(a1...ai)min(a1...ai),mini=1ndi.

题解

区间dp.
先把序列排序,观察发现最终答案的尾部必定是最大值或者最小值,从而整个序列的前 i i i个数必然是从小到大的一个区间.
并且对于 [ l , r ] [l,r] [l,r]这一段,最后一个 d d d必然等于 a r − a l a_r-a_l aral,从而我们只需要知道 [ l , r − 1 ] [l,r-1] [l,r1] [ l + 1 , r ] [l+1,r] [l+1,r]的答案并取最小值即可.
借助记忆化搜索,复杂度为 n 2 n^2 n2.

#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int aoi=2048;
typedef ll yuri[aoi];
yuri dp[aoi],a;
ll dfs(int l,int r) {
  if (l==r) return 0;
  if (~dp[l][r]) return dp[l][r];
  return dp[l][r]=a[r]-a[l]+min(dfs(l,r-1),dfs(l+1,r));
}
int main() {
  int i,n;
  read(n);
  memset(dp,-1,sizeof dp);
  for (i=1;i<=n;++i) read(a[i]);
  sort(a+1,a+n+1);
  printf("%lld\n",dfs(1,n));
}

D

题意

给出三个长度为 2 n 2n 2n 01 01 01字符串,构造一个长度不超过 3 n 3n 3n的字符串使至少有两个字符串是它的子序列.

题解

观察发现三个字符串中必然有两个字符串满足 0 0 0或者 1 1 1的数量 ≥ n \geq n n,由抽屉原理可证.
借助这个条件,我们直接用这两个字符串构造答案,令它们中重复 ≥ n \geq n n的字符为 p p p.
同时用 i , j i,j i,j两个指针扫描两个字符串,如果 a i = b j a_i=b_j ai=bj,则在答案中加入这个字符.
否则在答案中加入 1 − p 1-p 1p这个字符,并且将 a i a_i ai b j b_j bj中等于 1 − p 1-p 1p的这个位置向后移.
由于重复 p p p的数量 ≥ n \geq n n,答案字符串比起 2 n 2n 2n延长的长度 ≤ n \leq n n,符合要求.

#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int yuzu=3e5;
typedef char fuko[yuzu|10];
typedef int yuri[yuzu|10];
fuko a,b,c,zw;
yuri id,vis;
int main() {
  for (int t=read();t--;) {
    int n=read(),i;
    scanf("%s%s%s",a+1,b+1,c+1);
    for (i=1;i<=n*3+1;++i) zw[i]=0;
    auto cal=[&](char *a,char p) {
      int ans=0;
      for (i=1;i<=n*2;++i) ans+=a[i]==p;
      return ans;
    };
    auto work=[&](char *a,char *b) {
      for (auto p:{'0','1'}) {
        if (cal(a,p)>=n&&cal(b,p)>=n) {
          int la=1,lb=1,len=0;
          for (;la<=2*n&&lb<=2*n;) {
            if (a[la]==b[lb]) {
              zw[++len]=a[la],++la,++lb;
            } else {
              zw[++len]=a[la]==p?b[lb++]:a[la++];
            }
          }
          for (i=la;i<=n*2;++i) zw[++len]=a[i];
          for (i=lb;i<=n*2;++i) zw[++len]=b[i];
          puts(zw+1);
          return 1;
        }
      }
      return 0;
    };
    work(a,b)||work(a,c)||work(b,c);
  }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值