01串1: count 1
source: arc137_b
给定一个长度为 的由 组成的整数序列 。你可以做以下的操作一次且仅一次:
- 选择 的一个连续的子段,对该子段进行反转操作,也就是将 变成 ,将 变成 。注意,你可以选择一个空字段,这就相当于你什么都没有做。
最后 中的 的个数,是你能获得的分数。请问你有多少种可能的得分。
样例 #1
样例输入 #1
4
0 1 1 0
样例输出 #1
4
样例 #2
样例输入 #2
5
0 0 0 0 0
样例输出 #2
6
样例 #3
样例输入 #3
6
0 1 0 1 0 1
样例输出 #3
3
提示
analysis:
首先,这道题修改一下问题,通过一次区间修改,可以得到最多的1的个数是多少。
我们可以暴力的去想,枚举[l,r],进行翻转,原始序列中1的个数sum, 要减去区间内1的个数,加上区间内0的个数。我们可以用前缀和o(1)求出区间内0的个数和1的个数。然后减去1的个数,加上0的个数。求一个max,60分。
减去区间内1的个数,加上区间内0的个数,就是+1,-1操作。
于是有:假设你取了一段区间 [l,r],无论你下次取 [l−1,r]、[l+1,r]、[l,r−1] 还是 [l,r+1],都会对 ans 产生 1 的影响。这样的结论。
那么ans 的取值范围肯定是一段连续的正整数。
我们将原始序列中是1的地方,设b[]数组为-1,原数组是0的地方b[]数组是1。
原始序列中1的个数sum + b数组最大连续和,即为一次区间修改后的最多1的个数值。
同理,sum + b数组最小连续和,即为一次区间修改后的最少1的个数值。
最小~最大,就是得分的种类。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, a[300005], b[300005], maxn, minn, ansmax, ansmin;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), b[i] = b[i - 1] + (a[i] == 0 ? 1 : -1);
for (int i = 1; i <= n; i++) {
ansmax = max(ansmax, b[i] - minn);
//b[i]-minn 就是以当前节点为结尾所能产生的最大值
ansmin = min(ansmin, b[i] - maxn);
//b[i]-maxn 就是以当前节点为结尾所能产生的最小值
maxn = max(maxn, b[i]);
minn = min(minn, b[i]);
}
printf("%d", ansmax - ansmin + 1);
return 0;
}
01串2:「KDOI-07」n1gr tS0i
source: P10877 「KDOI-07」n1gr tS0i
题目背景
众所周知,小 T 不喜欢 01 串问题,于是小 R 出了另一个有关 01 串的题目:
题目描述
有一个长度为 的 串 ,你要对 进行 恰好 次操作。每次操作选择 ,然后你按位翻转 。这里的按位翻转指, 内所有 同时变为 ,且所有 同时变为 。
求 次操作后,所有可能不同的 的个数。因为答案可能很大,所以请对 取模。
输入格式
本题有多组数据。
第一行一个整数 描述数据组数。对于每组数据:
- 第一行一个整数 。
- 接下来一行,一个长度为 的 串 。
输出格式
对于每组数据,一行一个整数,表示答案,对 取模后的结果。
样例 #1
样例输入 #1
2
2
01
30
101001001010100110101101011110
样例输出 #1
1
75497471
提示
样例解释
- 对于 ,,我们会发现每次操作只能选择 即反转整串,因此 次操作后只能得到 ,故答案为 ;
- 对于第二组数据,暂时不能给你一个明确的答复。
数据规模与约定
本题采用捆绑测试。
分数 | ||
---|---|---|
对于所有数据,保证 ,,。
Analysis:
这里有一个很重要的条件L<R,如果L等于R,是不是每一个01序列都可以有种。现在尝试找规律:
我们可以用两次操作将一个n>=4的序列任意一位通过两次变化变为0或者1,比如“10110”的第4位,我想让它变成0,可以将它放在一个三位区间的最右侧,就是[011],这样,我们将这个区间翻转成100,那么第4位的1已经变成0了,达到我们的预期了。但是前两个数字也被我们修改了,于是我们把[10]再次翻转,就变成了原来的[01]。如果我想让第4位不变,只需要翻转包含它的两位数字两次,相当于没有修改。
如果要修改两位,其余都不变,比如10110中的[11],也是可以两次,[1011]变成[0100]再变成[1000]。
这个序列一定是要更改一些连续区间段,[]...[]....[],每一个连续区间段至少可以用2次更改,最多分成n/2个区间段,这样有2*n/2去更改成对立状态。
总状态是2^n.
如果n==3,则中间的哪位没有办法用上述方法修改。因为修改的数字要放在区间的边上。
n<=3的单独算一下即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人