社论:「LibreOJ Round #9」Menci 的序列
0
原题。
把题解翻译成人话。(?)
假做法 80pts,神秘。
1
注意到 ++ 和 +* 在形式上等价,所以从后往前把所有 *+++ 替换成 +*+ 不劣。
但是不能直接把加号段删空,hack:\(n=5,k=3\),+*++*。
为了处理开头的 +,先在开头加入若干个 * 不影响结果。
此时所有的连续加号段的长度都不超过二。如果加号段的数量 \(\ge k\) 直接取 +*+*+*+ 即可达到最大值全 1。
否则答案操作序列存在一个分界线,前缀为 +*+*+*+** 状物(也就是答案前缀全 1),后面不管是什么全部都取上并进位。
证明大概是:考虑前缀这个加乘交替的结尾一定是 +**,因为如果是两个加号就给前面全进位了。因为有两个乘号,所以后面怎么取都不可能进位到前面,此时全部取上最大。
分界线为刚好取满所有加号段并且答案长度为 \(k\) 的时候,此时答案的前缀 1 能顶到最高位并且最长。
2
代码
#include<bits/stdc++.h>
constexpr int rSiz=1<<21;
char rBuf[rSiz],*p1=rBuf,*p2=rBuf;
#define gc() (p1==p2&&(p2=(p1=rBuf)+fread(rBuf,1,rSiz,stdin),p1==p2)?EOF:*p1++)
template<class T>void rd(T&x){
char ch=gc();
for(;ch<'0'||ch>'9';ch=gc());
for(x=0;ch>='0'&&ch<='9';ch=gc())
x=(x<<1)+(x<<3)+(ch^48);
}
constexpr int _=1e6+105;
int n,m,k,a[_],b[_],c[_];
int main(){
rd(n),rd(k);m=100;
bool ok=0;
for(int i=1;i<=n;++i){
char ch=gc();
if(i==n+1)for(;ch^'*'&&ch^'+';ch=gc());
if(ch=='+')++a[m],ok=1;
else ++m;
}
if(!ok)return printf("0\n"),0;
memcpy(b,a,sizeof b);
for(int i=m;i;--i){
b[i-1]+=b[i]>>1;b[i]&=1;
a[i-1]+=a[i]>>1;
if(a[i]&1)a[i]=1;
else if(a[i])a[i]=2,--a[i-1];
}
for(int i=1;i<=m;++i)c[i]=c[i-1]+(a[i]>0);
if(c[m]>=k){
for(int j=k;j;--j)printf("1");
return printf("\n"),0;
}
for(int i=m;i;--i){
if(c[i-1]+m-i+1==k){
ok=0;
for(int j=c[i-1];j;--j)printf("1"),ok=1;
for(int j=i;j<=m;++j){
if(b[j])ok=1;
if(ok)printf("%d",b[j]);
}
return printf("\n"),0;
}
}
ok=0;
for(int j=1;j<=m;++j){
if(b[j])ok=1;
if(ok)printf("%d",b[j]);
}
return printf("\n"),0;
}

浙公网安备 33010602011771号