本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
【Codeforces】Educational Codeforces Round 137 - D. Problem with Random Tests
题目连接
题目大意
给你一个由 个字符组成的字符串 。 的每个字符都是 0 或 1。 每一位有 的概率是 1 ,随机生成。
选择 的任意两个连续子序列(即子串,两个子串可能相交,可能相同,可能不相交)。选择它们后,您计算所选子串对的值,如下所示:
令 为第一个子串, 为第二个子串,将他们视为正整数的二进制表示,如 表示 26。最大化 ,以二进制表示形式打印,不带前导零。
思路
首先为了让答案最大,我们肯定要让串尽可能长,第一个串肯定取 中第一个 出现的位置到 所有的字符。此时我们已经确定了 ,接下来我们求 。
然后为了最大化解,我们想把 最高位的 0 变成 1。记整个串 中第一个 1 出现的位置是 ,整个串 里出现 1 之后的第一个 0 的位置是 ,则第二个串的长度 就是 。
枚举 中所有长度为 的第一个数字是 1 的子串,看看和 的或能不能更新答案。易知原串中长度为 的子串数量为 ,即 中第一个 1 出现后连续出现的 1 的数量。因为 中的 0 或 1 是随机生成的,因此原串中长度为 的子串数量会很少。
代码
#include <bits/stdc++.h>
using namespace std;
using LL=long long;
typedef pair<int,int> PII;
const int N=1000001;
int n,m,k;
int a[N],ans[N];
int solve()
{
scanf("%d",&n);
m=k=0;
int f0=0;//第一个串的第一个0
for (int i=1;i<=n;++i)
{
scanf("%1d",&a[i]);
if (m==0&&a[i]) m=i;
if (k==0&&m&&!a[i]) f0=k=i;
ans[i]=0;
}
if (m==0)
{
printf("0");
return 0;
}
if (k==0)
{
for (int i=1;i<=n;++i) printf("1");
return 0;
}
for (int i=m;i<f0;++i) printf("%d",a[i]);
k=n-k+1;//k第二个串的长度
for (int i=m;i+k-1<=n;++i)//i第二个串的起点
{
if (!a[i]) continue;
int flag=0;
for (int j=0;j<k;++j)
{
if (flag) ans[j]=(a[i+j]|a[f0+j]);
if ((a[i+j]|a[f0+j])<ans[j]) break;
if ((a[i+j]|a[f0+j])>ans[j]) flag=1;
ans[j]=(a[i+j]|a[f0+j]);
}
}
for (int i=0;i<k;++i) printf("%d",ans[i]);
printf("\n");
}
int main()
{
solve();
return 0;
}