射命丸文的取材之旅
原题传送门
题目描述
给定序列 { a n } , { b n } \{a_n\},\{b_n\} {an},{bn},求一个序列 { c n } \{c_n\} {cn} 满足 ∀ i ∈ [ 1 , n ] , c i ∈ { a i , b i } \forall i\in[1,n],c_i\in\{a_i,b_i\} ∀i∈[1,n],ci∈{ai,bi},最大化
max { r − l + 1 − mex { c l , c l + 1 , … , c r − 1 , c r } } ( 1 ≤ l ≤ r ≤ n ) \max\{r-l+1-\operatorname{mex}\{c_l,c_{l+1},\dots, c_{r-1},c_r\}\}(1\le l\le r\le n) max{r−l+1−mex{cl,cl+1,…,cr−1,cr}}(1≤l≤r≤n)
并输出该式子可能的最大值。
输入格式
第一行一个正整数 n n n,表示每一份新闻中的新闻条数。
第二行 n n n 个非负整数表示第一份新闻中每一条新闻的吸引力,即 a 1 , a 2 … , a n − 1 , a n a_1,a_2\dots ,a_{n-1},a_n a1,a2…,an−1,an。
第三行 n n n 个非负整数表示第二份新闻中每一条新闻的吸引力,即 b 1 , b 2 … , b n − 1 , b n b_1,b_2\dots ,b_{n-1},b_n b1,b2…,bn−1,bn。
输出格式
输出一个整数,表示报刊的最大的综合影响力会是多少。
思路
-
对于20pts,可以暴力求解。
-
对于另外的 40 p t s 40pts 40pts,因为 ∀ i ∈ [ 1 , n ] , c i ∈ { a i , b i } \forall i\in[1,n],c_i\in\{a_i,b_i\} ∀i∈[1,n],ci∈{ai,bi}所以数列c唯一,我们考虑将序列中出现的数字标红,将未出现过的数字标黑 ,可以发现,红色数字将整个序列分解成了很多个黑色的段,而且显而易见黑色段里的 m e x mex mex小于等于红色数字。然后,我们考虑枚举 m e x mex mex ,(小于等于不好处理)就假设红色数字是前面黑色段子的 m e x mex mex,(贪心的选择最大的子段长度,就是上一次出现的红色数字的位置+1到当前枚举到的红色数字-1,这里处理了前面及中间的黑色段子),最后再枚举一遍1到n,取他们为 m e x mex mex,更新答案,取上一次 x x x出现的地方+1到n。(这里处理了后面的黑色段子)。
你可能会发现,这可能会枚举到虚假的答案,即 m e x mex mex是小于红色数字的。但这不重要,这种虚假的答案会被更优的答案覆盖掉。
如: c = 1 , 1 , 4 , 5 , 1 , 4 c={1,1,4,5,1,4} c=1,1,4,5,1,4
那么,枚举到最后一个4的时候,取得子段就是 5 , 1 {5,1} 5,1,可, m e x ( 5 , 1 ) mex(5,1) mex(5,1)应是0,可我们假设的 m e x mex mex是4,不符合要求,但这无妨,因为计算出来的贡献是 − 2 -2 −2根本无法更新答案。接着举例,你会发现,这个虚假的 m e x mex mex所造成虚假的贡献要么都无法覆盖前面的答案,要么会被后面的答案覆盖掉,因此,正确性可以保证。
code
#include<bits/stdc++.h> using namespace std; int n,a[1000007],b[1000007],l[1000007],ans; int main(){ cin >> n; for (int i = 1;i <= n;i++) cin >> a[i]; for (int i=1;i<=n;i++) cin >> b[i]; for (int i=1;i<=n;i++){ ans=max(ans,i - l[a[i]] - 1 - a[i]); /* 上一次出现的位置是l[a[i]],这一次出现的位置是i, 而原式是 (i-1) - (l[a[i]]+1) -1 - a[i], 化简就是 i - l[a[i]] - 1 - a[i]。 */ l[a[i]] = i; // 将a[i]出现的位置记下方便下一次操作 } for (int i = 0;i <= n;i++) ans = max(ans,n - l[i] - i); /* 原式n - (l[i] + 1) - 1 - i; */ cout << ans << endl; return 0; }
-
对于 100 p t s 100pts 100pts,我们发现,可以选择 a i 或 b i a_i或b_i ai或bi,即序列 c i c_i ci不一定。但通过观察我们可以发现,只有 a i = b i a_i=b_i ai=bi时才会有可能影响到我们的 m e x mex mex,其他数字没有影响。所以,我们考虑延续前面的做法,但我们的红色数字仅在 a i = b i a_i=b_i ai=bi时将这个数字标红,将其他数字标黑,然后还是假设 m e x mex mex等于红色数字,照上文枚举即可。
Code
#include<bits/stdc++.h>
using namespace std;
int n,a[1000007],b[1000007],l[1000007],ans;
int main(){
cin >> n;
for (int i = 1;i <= n;i++)
cin >> a[i];
for (int i=1;i<=n;i++)
cin >> b[i];
for (int i=1;i<=n;i++){
if(a[i] != b[i]) continue;
ans = max(ans,i - l[a[i]] - 1 - a[i]);
/*
上一次出现的位置是l[a[i]],这一次出现的位置是i,
而原式是 (i-1) - (l[a[i]]+1) -1 - a[i],
化简就是 i - l[a[i]] - 1 - a[i]。
*/
l[a[i]] = i; // 将a[i]出现的位置记下方便下一次操作
}
for (int i = 0;i <= n;i++)
ans = max(ans,n - l[i] - i);
/*
原式n - (l[i] + 1) - 1 - i;
*/
cout << ans << endl;
return 0;
}
补充
你可能会发现,删掉ans = max(ans,i - l[a[i]] - 1 - a[i])
这一行,代码仍然AC,这是为什么呢?
当然是因为数据水,不信你可以试一下这一组样例。
在这里插入代码片
6
1 2 3 4 5 6 0 1 2 3 4
1 2 3 4 5 6 0 1 2 3 4