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),求min∑i=1ndi.
题解
区间dp.
先把序列排序,观察发现最终答案的尾部必定是最大值或者最小值,从而整个序列的前
i
i
i个数必然是从小到大的一个区间.
并且对于
[
l
,
r
]
[l,r]
[l,r]这一段,最后一个
d
d
d必然等于
a
r
−
a
l
a_r-a_l
ar−al,从而我们只需要知道
[
l
,
r
−
1
]
[l,r-1]
[l,r−1]和
[
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
1−p这个字符,并且将
a
i
a_i
ai和
b
j
b_j
bj中等于
1
−
p
1-p
1−p的这个位置向后移.
由于重复
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);
}
}