列表

详情


NC19469. 01串

描述

I used to believe
We were burning on the edge of something beautiful
Something beautiful
Selling a dream
Smoke and mirrors keep us waiting on a miracle
On a miracle
Say go through the darkest of days
Heaven's a heartbreak away
Never let you go
Never let me down
OH it's been a hell of a ride
Driving the edge of a knife
Never let you go
Never let me down
Bieber拥有一个长度为n的01 串,他每次会选出这个串的一个子串作为曲谱唱歌,考虑该子串从左往右读所组成的二进制数P。 Bieber每一秒歌唱可以让P增加或减少 2 的 k次方(k由Bieber选定),但必须保证任意时刻其P大于等于0。
Bieber 是一位追求效率的人 每次Bieber都想知道他歌唱的最少时间将这个数P变成0。
Bieber 正和 一位DJ合作,他随时可能修改串上的一个字符。

输入描述

第一行一个数n
第二行一个长度为n的字符串s
第三行一个数 t 表示 询问 + 修改总次数
以下 t 行, 每行格式如下
第一个数 1 <= type <= 2 表示 类型
Type = 1 表示是一次 询问 接下来两个数 l , r 表示询问的区间。
否则 表示一次修改 接下来两个数x,y 表示把 s[x] 改为y.
n <= 3e5, t <= 3e5

输出描述

对于每个询问输出一个数表示最少次数。

示例1

输入:

4
1101
1
1 1 4

输出:

3

原站题解

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

C++14(g++5.4) 解法, 执行用时: 368ms, 内存消耗: 24028K, 提交时间: 2018-10-05 13:11:30

#include<bits/stdc++.h>
using namespace std;


const int MAX_N = 3e5 + 5;
struct nd {
	int m[2][2];
	nd(int x = 0) {
		m[0][1] = m[1][0] = 1;
		m[0][0] = x;
		m[1][1] = !x;
	}
}dat[MAX_N * 4];

int cnt = 0;
char s[MAX_N];
int n, q, a, b;

nd merge(nd a, nd b) {
	nd c;
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 2; j++) {
			c.m[i][j] = min(a.m[i][0] + b.m[0][j], a.m[i][1] + b.m[1][j]);
		}
	}
	return c;
}

void build(int l, int r, int k) {
	if (r - l == 1) {
	    dat[k] = nd(s[cnt++]^'0');
		return;
	}
	build(l, (l + r) >> 1, 2 * k + 1);
	build((l + r) >> 1, r, 2 * k + 2);
	dat[k] = merge(dat[2 * k + 1], dat[2 * k + 2]);
}

nd query(int a, int b, int l, int r, int k) {
	if (a <= l && r <= b) return dat[k];
	if (b <= l || a >= r) return nd(0);
	return merge(query(a, b, l, (l + r) >> 1, 2 * k + 1),
		query(a, b, (l + r) >> 1, r, 2 * k + 2));
}

void change(int l, int r, int k) {
	if (a < l || a >= r) return;
	if (r - l == 1) {
		dat[k] = nd(b);
		return;
	}
	change(l, (l + r) >> 1, 2 * k + 1);
	change((l + r) >> 1, r, 2 * k + 2);
	dat[k] = merge(dat[2 * k + 1], dat[2 * k + 2]);
}

int main() {
	cin >> n; scanf("%s", &s);
	build(0, n, 0);
	cin >> q;
	int t;
	for (int i = 0; i < q; i++) {
		scanf("%d%d%d", &t, &a, &b);
		if (t == 1) {
			printf("%d\n",query(a - 1, b, 0, n, 0).m[0][0]);
		}
		else {
			a--;
			change(0, n, 0);
		}
	}
}

C++11(clang++ 3.9) 解法, 执行用时: 339ms, 内存消耗: 21472K, 提交时间: 2018-10-29 16:50:54

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=3e5+10;
int n,q,A[N];char s[N];
struct Mat {int a[4];Mat(){a[0]=a[1]=a[2]=a[3]=0;}}t[N<<2];
Mat operator + (Mat A,Mat B)
{
	Mat C;
	C.a[0]=min(A.a[0]+B.a[0],A.a[1]+B.a[2]);
	C.a[1]=min(A.a[0]+B.a[1],A.a[1]+B.a[3]);
	C.a[2]=min(A.a[2]+B.a[0],A.a[3]+B.a[2]);
	C.a[3]=min(A.a[2]+B.a[1],A.a[3]+B.a[3]);
	return C;
}
void Get(Mat &A) {A.a[0]=A.a[1]=A.a[2]=A.a[3]=1;}
void build(int now,int l,int r,int p,int v)
{
	if(l==r)
	{
		if(p) A[l]=v;Get(t[now]);
		t[now].a[A[l]?3:0]=0;
		return;
	}
	int mid=(l+r)>>1;
	if(!p||p<=mid) build(now<<1,l,mid,p,v);
	if(!p||p>mid) build(now<<1|1,mid+1,r,p,v);
	t[now]=t[now<<1]+t[now<<1|1];
}
Mat Query(int now,int l,int r,int gl,int gr)
{
	if(l>=gl&&r<=gr) return t[now];
	int mid=(l+r)>>1;
	if(gr<=mid) return Query(now<<1,l,mid,gl,gr);
	if(gl>mid) return Query(now<<1|1,mid+1,r,gl,gr);
	return Query(now<<1,l,mid,gl,gr)+Query(now<<1|1,mid+1,r,gl,gr);
}
int main()
{
	scanf("%d%s%d",&n,s+1,&q);
	for(int i=1;i<=n;i++) A[i]=s[i]=='1';
	build(1,1,n,0,0);
	while(q--)
	{
		int op,x,y;scanf("%d%d%d",&op,&x,&y);
		if(op==1) printf("%d\n",Query(1,1,n,x,y).a[0]);
		else if(A[x]!=y) build(1,1,n,x,y);
	}
	return 0;
}

上一题