1 条题解
-
0
P12505 「ROI 2025 Day2」充实的假期
标签:贪心,分类讨论。
前置知识:小学数学,
for,if。题面
给一个
01字符串,每次问插入 个1,求最多的连续的1的数目(当有两个及以上的1在一起,他们就是连续的1)。思路
注意到求
1的数目而不是最大长度,所以考虑每次加1的贡献最大的直接贪心,即贡献越大越优先,可进行分类讨论。(按贡献从大到小):
-
形如
101,发现如果将中间的0填补,有 个贡献。 -
形如
10或01,发现将中间(旁边?)的0填补,有 个贡献。 -
形如
0,将其填充获得 个贡献。
特别的,不能重复贡献,所以设置 个
vis数组记录是否已经算进贡献里了。其中的第 点中形如
0填充的可以算 个贡献其实并不需要考虑是否连续,因为按照优先级肯定可以到有1的旁边达成连续。这种情况也有特殊,如全是0,需要进行特判。代码
欣赏吧。
#include<bits/stdc++.h> const int M=1e5+5;; using namespace std; int n,q,ans=0,a1=0,a2=0,a3=0,ys=0; bool vis[M];//不能重复贡献 string c; void calc(){//计算每一种 010,01,0 的个数 for(int i=1;i<c.size();i++){ if(!vis[i]&&c[i-1]=='1'&&!vis[i-1]&&c[i]=='0'&&c[i+1]=='1'&&!vis[i+1]){a1++;vis[i-1]=1;vis[i]=1;vis[i+1]=1;} } for(int i=1;i<c.size();i++){ if(!vis[i]&&c[i-1]=='1'&&!vis[i-1]&&c[i]=='0'){a2++;vis[i-1]=1;vis[i]=1;} else if(!vis[i]&&c[i+1]=='1'&&!vis[i+1]&&c[i]=='0'){a2++;vis[i+1]=1;vis[i]=1;} } } int query(int sl){//O(1)进行计算 if(ys==0)return sl<=1?0:sl; if(sl<=a1)return sl*3; if(sl>a1&&sl<=a1+a2)return a1*3+(sl-a1)*2; return a1*3+a2*2+sl-a1-a2; } int main(){ memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&q); cin>>c; for(int i=0;i<c.size();i++)if(c[i]=='1')ys++; for(int i=1;i<c.size();i++){ if(c[i]=='1')ys++; if(c[i]=='1'&&c[i-1]=='1'){ if(!vis[i-1]){ ans++;vis[i-1]=1; } ans++;vis[i]=1; } } calc(); // cout<<a1<<' '<<a2<<'\n'; // 调试代码 while(q--){ int x;scanf("%d",&x); printf("%d\n",ans+query(x)); } } -
- 1
信息
- ID
- 9583
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者