对于求从 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)。快速求和就要用到——前缀和。
定义 x i x_i xi 为 S u b ( 1 , i ) Sub(1,i) Sub(1,i)。计算公式为上一位( x i − 1 x_{i-1} xi−1)的数乘 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' xi←xi−1+si−′0′。
但 x i x_i xi 仅仅只能计算 S u b ( 1 , i ) Sub(1,i) Sub(1,i),但不能通过 x r − x l x_r-x_l xr−xl 计算任意的 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} xr−xl×2r−l+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 pow2i←pow2i−1×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;
}
定义 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' yi←yi−1+si−′0′。
代码:
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;
}
原文链接