Manci的序列题解
的序列
题意:你有一个长为 n 的序列,每个位置是 *
或者 +
,*
表示让变量 ,+
表示让变量 。现在你要选出它的一个子序列,使得一个初始为 0 的变量在对子序列中的字符依次执行对应操作后对 取模所得结果尽可能大。求出最大可能的结果。
:比较显然的一点,最后的值为, 表示一个加号后面乘号的个数。于是可以先考虑一种非常简单的特殊情况:任意两个乘号之间最多只有一个加号。可以从前往后直接贪心做,最开始填第 位,如果乘号不够就填第 位,如果足够就填 再考虑之后的加号,以此类推可以得到最优解。但是现在原问题两乘号之间会有多个加号,可以用二进制分组的思路,因为一个加号后有 个乘号相当于两个加号后有 个加号。
这里略微比较复杂,举一个例子原序列为+++
可替换为 +*+
,具体的,原序列选 +
等价于新序列选 +
,原序列选 ++
等价于新序列选 +*
原序列选 +++
等价于新序列选 +*+
。所以我们可以把后面有 个乘号的加号每两个换成一个后面有 的加号,但是不能全部转完,需要留下 个,否则原序列某些选择在新序列中找不到对应的选法。
就这样我们把原序列转化成了连续加号个数不超过 个的特殊序列。只有一个的情况上面已经讲了,而两个也差不多,具体的,处理时如果前一位需要填 但没有加号了可以临时进位,否则就只需要在这一位填 即可。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
inline int rd()
{
char c;int f=1;
while(!isdigit(c=getchar()))if(c=='-')f=-1;
int x=c^48;
while(isdigit(c=getchar()))x=(x<<1)+(x<<3)+(c^48);
return x*f;
}
int a[N],ans[N],t,cnt,k,n,m,p;
char s[N];
int main()
{
n=rd(),k=rd();
scanf("%s",s+1);
for(int i=n;i;i--)
if(s[i]=='*') a[++cnt]=0;
else a[cnt]++;
for(int i=0;i<=n;i++)
{
if(!a[i]) continue;
t=(a[i]-1)/2;
a[i]-=2*t,a[i+1]+=t;
}
p=k-1;
for(int i=n;i;i--)
{
while(i>=0&&!a[i]) i--;
if(i<0) break;
if(i>=p) ans[p--]=1;
else
{
for(int j=0;j<p;j++){
t=a[j]/2;
a[j]-=2*t,a[j+1]+=t;
ans[j]=a[j];
}
ans[p]=a[p];
break;
}
}
p=k-1;
while(p>=0&&!ans[p]) p--;
if(p>=0) for(int i=p;i>=0;i--) printf("%d",ans[i]);
else printf("0");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通