bzoj 5294 Bjoi2018 二進位制

2022-05-11 01:21:06 字數 2803 閱讀 2661

pupil 發現對於乙個十進位制數,無論怎麼將其的數字重新排列,均不影響其是不是333 的倍數。他想研究對於二進

制,是否也有類似的性質。於是他生成了乙個長為n 的二進位制串,希望你對於這個二進位制串的乙個子區間,能求出

其有多少位置不同的連續子串,滿足在重新排列後(可包含前導0 )是乙個3 的倍數。兩個位置不同的子區間指開

始位置不同或結束位置不同。由於他想嘗試盡量多的情況,他有時會修改串中的乙個位置,並且會進行多次詢問。

假設知道結論:

當乙個二進位制數滿足以下任意條件則重排後不能 \(\mod 3=0\)

1.只出現了乙個 \(1\)

2.\(1\) 出現的次數為奇數,且 \(0\) 出現的為 \(0\)

3.\(1\) 出現的次數為奇數,且 \(0\) 出現的為 \(1\)

證明:\(1\) 容易證明

\(2,3\) 的話,我們首先要知道 \(2^2 \mod 3=1\) ,且 \(*2^2\) 之後依舊滿足

\(2^1 \mod 3=2\),且 \(*2^2\) 之後依舊滿足

所以有結論:放在偶數字可以貢獻 \(2\),放在奇數字貢獻 \(1\)

那麼如果 \(1\) 出現了偶數次那麼一定可以滿足條件,因為把 \(1\) 都放在後面,恰好可以構成數 \(2^k-1\),而 \(2^k \mod 3=1\)

那麼如果奇數字上放 \(1\) 的個數比偶數字多了 \(3\),那麼一定可以拼成滿足 \(\mod 3=0\)

因為奇偶配對之後 \(\mod 3=0\),剩下的奇數字 \(3*2 \mod 3=0\),所以恰好滿足

\(1\) 出現次數為奇數,且 \(0\) 出現次數為 \(>=3\),顯然滿足

\(1\) 出現次數為奇數,且 \(0\) 出現次數為 \(=2\),由於總共有奇數字,所以奇數比偶數本身就多 \(1\) ,也滿足

\(0\) 出現次數為 \(0,1\) 時 ,也顯然不滿足

綜上只需要維護不合法情況:

1.只出現了乙個 \(1\)

2.\(1\) 出現的次數為奇數,且 \(0\) 出現的為 \(0\)

3.\(1\) 出現的次數為奇數,且 \(0\) 出現的為 \(1\)

\(1\) 情況和 \(2,3\) 有交集,我們強制 \(1\) 條件為 "出現了乙個\(1\),且 \(0\) 出現了至少 \(2\) 次"

線段樹分別維護 \(dl/dr[2][2]\) 表示經過左/右端點,\(0\) 出現了 \(0/1\) 次,\(1\) 出現次數的奇偶性的方案數 (統計情況 \(2,3\))

\(fl/r[3]\) 表示經過左/右端點,\(1\) 恰好出現了 \(1\) 次,且 \(0\) 出現的次數分別為 \(0,1,>=2\) 的方案數 (統計情況 \(1\))

\(l/r0\) 表示經過左右端點的連續 \(0\) 的長度

\(c0,c1\)

\(0,1\) 的個數

#include#define ls (o<<1)

#define rs (o<<1|1)

using namespace std;

templatevoid gi(t &x)

typedef long long ll;

const int n=1e5+10;

int n,a[n],q,op,x,y;

struct data

data()

}tr[n*4];

inline data merge(data a,data b)

for(int i=0;i<3;i++)

if(a.c1==1 && b.l0)r.fl[min(2ll,a.c0+b.l0)]++,r.fl[2]+=b.l0-1;

if(b.c1==1 && a.r0)r.fr[min(2ll,b.c0+a.r0)]++,r.fr[2]+=a.r0-1;

r.l0=(!a.c1?a.c0+b.l0:a.l0);r.r0=(!b.c1?b.c0+a.r0:b.r0);

r.c0=a.c0+b.c0;r.c1=a.c1+b.c1;

r.s+=a.s+b.s;

r.s+=a.dr[0][1]*(b.dl[1][0]+b.dl[0][0]);

r.s+=a.dr[1][0]*b.dl[0][1];

r.s+=a.dr[0][0]*(b.dl[1][1]+b.dl[0][1]);

r.s+=a.dr[1][1]*b.dl[0][0];

if(b.l0)r.s+=(a.fr[2]+a.fr[1])*b.l0,r.s+=a.fr[0]*(b.l0-1);

if(a.r0)r.s+=(b.fl[2]+b.fl[1])*a.r0,r.s+=b.fl[0]*(a.r0-1);

return r;

}inline void rep(data &t,int x)

inline void build(int l,int r,int o)

int mid=(l+r)>>1;

build(l,mid,ls);build(mid+1,r,rs);

tr[o]=merge(tr[ls],tr[rs]);

}inline void ins(int l,int r,int o,int sa)

int mid=(l+r)>>1;

if(sa<=mid)ins(l,mid,ls,sa);

else ins(mid+1,r,rs,sa);

tr[o]=merge(tr[ls],tr[rs]);

}inline data qry(int l,int r,int o,int sa,int se)

int main()

} return 0;

}

BJOI2018 二進位制

題目鏈結 pupil 發現對於乙個十進位制數,無論怎麼將其的數字重新排列,均不影響其是不是 的倍數。他想研究對於二進位制,是否也有類似的性質。於是他生成了乙個長為n 的二進位制串,希望你對於這個二進位制串的乙個子區間,能求出其有多少位置不同的連續子串,滿足在重新排列後 可包含前導0 是乙個3 的倍數...

BJOI2018 二進位制

題目位址 前置知識 線段樹 給定乙個長度為 n 的 01 串,m 次操作 先來解決乙個子問題,什麼樣的序列重排是 3 的倍數?設 s 為序列上 1 的個數,序列長度為 len 將二進位制下每位下的權列列舉出來,分別是 1,2,4,8,16,32.換成 bmod 3 意義下的權 1,2,1,2,1,2...

BJOI2018 二進位制

題目鏈結 pupil 發現對於乙個十進位制數,無論怎麼將其的數字重新排列,均不影響其是不是 的倍數。他想研究對於二進位制,是否也有類似的性質。於是他生成了乙個長為n 的二進位制串,希望你對於這個二進位制串的乙個子區間,能求出其有多少位置不同的連續子串,滿足在重新排列後 可包含前導0 是乙個3 的倍數...