洛谷题解:P12465 『FCRT / 1 - 2』Parity

题意

对于求从 0 0 0 Sub ⁡ ( l , r ) \operatorname{Sub}(l,r) Sub(l,r) 的每一个 x x x,求 Pari ⁡ ( x ) \operatorname{Pari}(x) Pari(x)

思路

由于数据太恶心,所以需要找到一种方法快速求出 Pari ⁡ ( 0 ) \operatorname{Pari}(0) Pari(0) Pair ⁡ ( Sub ⁡ ( l , r ) ) \operatorname{Pair}(\operatorname{Sub}(l,r)) Pair(Sub(l,r)) 的和还有 Sub ⁡ ( l , r ) \operatorname{Sub}(l,r) Sub(l,r)。快速求和就要用到——前缀和。

Sub ⁡ \operatorname{Sub} Sub 的快速计算

定义 x i x_i xi S u b ( 1 , i ) Sub(1,i) Sub(1,i)。计算公式为上一位( x i − 1 x_{i-1} xi1)的数乘 2 2 2(由于是二进制,所以位权是 2 2 2,因此乘 2 2 2)加上当前为的值(零或一,因为是二进制)。也就是 x i ← x i − 1 + s i − ′ 0 ′ x_i\gets x_{i-1}+s_i-'0' xixi1+si0
x i x_i xi 仅仅只能计算 S u b ( 1 , i ) Sub(1,i) Sub(1,i),但不能通过 x r − x l x_r-x_l xrxl 计算任意的 S u b ( l , r ) Sub(l,r) Sub(l,r)。需要用 x r − x l × 2 r − l + 1 x_r-x_l\times2^{r-l+1} xrxl×2rl+1(就是将 x l x_l xl 乘以与其对应的位权)。但计算 2 n 2^n 2n 也很费时间,所以干脆也用 p o w 2 i pow2_i pow2i 数组存储 2 i 2^i 2i。计算公式: p o w 2 i ← p o w 2 i − 1 × 2 pow2_i\gets pow2_{i-1}\times2 pow2ipow2i1×2
代码:

int sub(int l,int r){
    if(l>r)return 0;
    return ((x[r]-x[l-1]*pow2[r-l+1])%mod+mod)%mod;
}
Pari ⁡ \operatorname{Pari} Pari 的快速计算

定义 y i y_i yi 为从第一位到第 i i i 为的一的数量。计算方法为上一位的加当前这位的数。计算公式: y i ← y i − 1 + s i − ′ 0 ′ y_i\gets y_{i-1}+s_i-'0' yiyi1+si0
代码:

int pari(int l,int r){
    return (y[r]-y[l-1])%2;
}
预处理
pow2[0]=1;
for(int i=1;i<=n;i++)
  pow2[i]=pow2[i-1]*2ll%mod,
  x[i]=(x[i-1]*2ll+s[i]-'0')%mod,
  y[i]=y[i-1]+s[i]-'0';
主函数

由于 2 n 2n 2n 2 2 2 的倍数,所以 2 n 2n 2n 的末尾为 0 0 0,因此 2 k 2k 2k 2 n + 1 2n+1 2n+1 的一的个数相差 1 1 1,所以必定一个是奇数,一个是偶数。于是,本题变成求 Sub ⁡ ( l , r ) \operatorname{Sub}(l,r) Sub(l,r) 的奇偶性。
代码:

while(q--){
	cin>>l>>r;
	if(s[r]=='1') cout<<(sub(l,r-1)+1)%mod<<'\n';
	else cout<<(sub(l,r-1)+pari(l,r))%mod<<'\n';
}

代码实现

#include
using namespace std;
long long n,q,l,r,pow2[200001],x[200001],y[200001];
const int mod=998244353;
char s[200001];
int sub(int l,int r){
    if(l>r)return 0;
    return ((x[r]-x[l-1]*pow2[r-l+1])%mod+mod)%mod;
}
int pari(int l,int r){
    return (y[r]-y[l-1])%2;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>q>>(s+1);
	pow2[0]=1;
	for(int i=1;i<=n;i++)
		pow2[i]=pow2[i-1]*2ll%mod,
		x[i]=(x[i-1]*2ll+s[i]-'0')%mod,
		y[i]=y[i-1]+s[i]-'0';
	while(q--){
		cin>>l>>r;
		if(s[r]=='1') cout<<(sub(l,r-1)+1)%mod<<'\n';
		else cout<<(sub(l,r-1)+pari(l,r))%mod<<'\n';
	}
	return 0;
}

原文链接

你可能感兴趣的:(题解,算法)