列表

详情


NC224109. 零一奇迹

描述

小红拿到了一个长度为 的 01 串(仅由字符 '0' 和 '1' 组成的字符串)。
小红想知道,有多少子串满足,其所表示的二进制数,其对应的十进制数值在 之间(只统计不含前导零的子串)?

注 1 :两个子串哪怕长的一模一样,但只要取的位置不同,则定义为 2 个不同子串
注 2 :所谓子串(substring),指字符串删掉部分前缀和后缀(也可以不删)形成的字符串。

这个问题小红觉得可能太简单了,于是她决定强化该问题:
她可能会添加一些修改操作:每次选择一个位置进行翻转,即将 0 变成 1 或者 1 变成 0 。

她希望每次修改操作之后,你可以回答“有多少子串满足,其所表示的二进制数,其对应的十进制数值在 之间?”这个问题的答案。
注:每次操作之后,字符串就会发生改变(即影响以后的询问)

输入描述

第一行三个正整数
第二行为一个长度为 的 01 串。
第三行为一个正整数 。代表修改的次数

接下来的 行,每行有一个正整数 ,代表翻转第 位置上的字符。



输出描述

一共输出 行,每行一个整数,代表每次操作之后问题的答案。
请注意,每次操作后字符串的改动是会持续到未来的询问的。

示例1

输入:

5 2 4
10100
5
5
5
4
3
4

输出:

2
3
3
3
2

说明:

翻转 5 号位置以后, 字符串为10101,可能的结果有 10101 , 10101
翻转 5 号位置以后, 字符串为10100,可能的结果有 10100 , 10100 , 10100
翻转 4 号位置以后, 字符串为10110,可能的结果有 10110 , 10110 , 10110
翻转 3 号位置以后, 字符串为10010,可能的结果有 10010 , 1001010010
翻转 4 号位置以后, 字符串为10000,可能的结果有 10000 , 10000

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 144ms, 内存消耗: 748K, 提交时间: 2023-05-01 21:37:07

#include<iostream>
using namespace std;
#define rep(i,l,r) for(int i = l; i <= r; i++)
#define fep(i,a,b) for(int i=b; i>=a; --i)
typedef long long ll;

string s;
ll n, l, r, q;

ll cul(int L, int R)
{
	ll ans = 0;
	rep(i,L,R)
	{
		if(s[i]=='0') continue;

		ll tmp = 0;

		for(int j=1;j<=64 and i+j-1<=n; j++)
		{
			int now = i + j - 1;
			tmp = (tmp<<1) + (s[now]-'0');
			if(tmp >= l and tmp <= r) ans++;
			if(tmp > r) break;
		}
	}
	return ans;
}

void solve()
{

	cin >> n >> l >> r >> s >> q;

	s=" "+s;

	ll ans=0;
	rep(i,1,q)
	{
		int x; cin >> x;

		ll t1 = cul(max(1, x-63), x);

		s[x] = (s[x] == '0') ? '1' : '0';

		ll t2 = cul(max(1, x-63), x);

		if(i==1) ans = cul(1, n);

		else ans += t2 - t1;

		cout << ans << endl;
	}
}

int main()
{
	ios::sync_with_stdio(false);cin.tie(0);
	solve();
	return 0;
}

C++ 解法, 执行用时: 85ms, 内存消耗: 520K, 提交时间: 2021-08-08 11:17:15

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define Min(x,y)((x)<(y)?x:y)
#define Max(x,y)((x)>(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
ll l,r;
int n,k;
char s[100005];
void calc(int i,int type)
{
	int j;
	ll t=0;
	For(j,i,Min(i+65,n))
	{
		t=t<<1|(s[j]-'0');
		if(t>r)break;
		k+=(t>=l)*type;
	}
}
int main()
{
	int q,i,a;
	scanf("%d%lld%lld%s%d",&n,&l,&r,s+1,&q);
	For(i,1,n)
	if(s[i]=='1')calc(i,1);
	while(q--)
	{
		scanf("%d",&a);
		For(i,Max(a-65,1),a)
		if(s[i]=='1')calc(i,-1);
		s[a]='1'-s[a]+'0';
		For(i,Max(a-65,1),a)
		if(s[i]=='1')calc(i,1);
		printf("%d\n",k);
	}
	return 0;
}

上一题