题目背景
题目背景纯粹为吐槽,如果不想看的可以直接翻到最后。
宫水三叶在牛客上做题,她想知道牛客上的题目有多难。
三叶先找到一道全场最多人通过的,被公认为水题的题目:
给定 n n n ,请求出下列式子的值。
∫ 0 1 ( x − x 2 ) n d x \int_{0}^{1} (x-x^2)^n dx ∫01(x−x2)ndx
作为一个高中生,三叶并不会做这道题,并且认为它和 OI
的关系不大。
接着三叶看到了一道计数题,三叶认为这题和 OI
的关系比较大。
有 n + m n+m n+m 个点,其中前 n n n 个点为 x 1 , x 2 , … , x n x_1,x_2,\dots,x_n x1,x2,…,xn,后 m m m 个点为 y 1 , y 2 , … , y m y_1,y_2,\dots,y_m y1,y2,…,ym。
给定序列 a a a ,已知对于 x i x_i xi 和前 a i a_i ai 个 y y y 有边相连。
请计算生成树的方案。
三叶思考了一阵,尝试了动态规划,矩阵树定理和生成函数等多种方法,还是不会做。于是三叶点开了题解:
本题的答案是 [一个简单的式子] , 具体证明在 [一篇很长的论文] 中。
三叶认为这种论文题不应该出现在 OI
中,于是就点开了下一题:
平面几何是一种非常有趣的问题。比如下面两个问题:
例一:在圆 M M M 中有两条弦 A C AC AC 和 N T NT NT , M M M 到两条弦的距离相等。已知 ∠ M T N = 2 8 ∘ \angle MTN = 28 ^ \circ ∠MTN=28∘,求 ∠ M A C \angle MAC ∠MAC 。
例二:在 △ A D E \triangle ADE △ADE 中, B B B 在 A E AE AE 上, C C C 在 A D AD AD 上,且 B C / / D E BC // DE BC//DE。若 A C = x − 3 , B E = 20 , A B = 16 , C D = x + 5 AC=x-3,BE=20,AB=16,CD=x+5 AC=x−3,BE=20,AB=16,CD=x+5,求 x x x 的值。
现在输入一道平面几何问题,请编写程序解决它。
看到这道题 17 17 17 人提交 0 0 0 人通过,三叶想起了以前有一位爱出斗地主和麻将的出题人。
三叶不想在牛客上继续写题了,便发誓如果下一题还这么奇怪,就放弃写题。
于是三叶点开了下一题。
题目描述
给定一个长度为 n n n 的序列 a a a。
定义 F ( l , r ) = a l & a l + 1 & ⋯ & a r F(l,r)=a_l \And a_{l+1} \And \dots \And a_r F(l,r)=al&al+1&⋯&ar。
其中
&
\And
& 为二进制下 AND
操作。
定义集合 S ( l , r ) = { F ( x , y ) ∣ m i n ( l , r ) ≤ x ≤ y ≤ m a x ( l , r ) } S(l,r)=\{F(x,y)|min(l,r)\le x\le y\le max(l,r)\} S(l,r)={F(x,y)∣min(l,r)≤x≤y≤max(l,r)}。
给定 q q q 次询问,每次输出 S ( l , r ) S(l,r) S(l,r) 的大小(即集合中的元素个数)。
并且要求强制在线。方式如下:
记 l a s t a n s lastans lastans 为上一次的答案,初始为 0 0 0 。
输入
L
,
R
L,R
L,R,
l
=
(
L
⊕
l
a
s
t
a
n
s
)
%
n
+
1
,
r
=
(
R
⊕
l
a
s
t
a
n
s
)
%
n
+
1
l=(L\oplus lastans)\%n+1,r=(R\oplus lastans)\%n+1
l=(L⊕lastans)%n+1,r=(R⊕lastans)%n+1。其中
⊕
\oplus
⊕ 为二进制下 XOR
操作。
第一行两个整数 n , o p n,op n,op 。
接下来一行 n n n 个整数,表示序列 a a a 。
接下来一行一个整数 q q q ,表示询问数。
接下来 q q q 行,每行 2 2 2 个整数。
如果 o p = 0 op=0 op=0 ,则表示不要求强制在线。否则表示要求强制在线。
具体操作为当 o p = 0 op=0 op=0 时,在每一次询问前都把 l a s t a n s lastans lastans 赋值为 0 0 0 ,否则不做操作。
而输入仍然为 L , R L,R L,R , l , r l,r l,r 的计算式仍为 l = ( L ⊕ l a s t a n s ) % n + 1 , r = ( R ⊕ l a s t a n s ) % n + 1 l=(L\oplus lastans)\%n+1,r=(R\oplus lastans)\%n+1 l=(L⊕lastans)%n+1,r=(R⊕lastans)%n+1 。
共输出 q q q 行,第 i i i 行表示第 i i i 个询问的答案。
样例输入 1
5 1
15 14 13 11 7
3
2 5
2 5
2 5
样例输出 1
4
1
3
样例输入 2,3
见下发文件。
样例二满足 o p = 0 op=0 op=0 ,样例三满足 o p = 1 op=1 op=1。
本题采用捆绑测试,每个子任务 10 10 10 分。
对于所有数据,满足 1 ≤ n ≤ 1 0 5 , 0 ≤ a i < 2 30 , 1 ≤ q ≤ 1 0 5 , 0 ≤ L , R < 2 30 , o p ∈ { 0 , 1 } 1\le n \le 10^5 ,0\le a_i < 2^{30},1\le q \le 10^5,0\le L,R < 2^{30},op\in\{0,1\} 1≤n≤105,0≤ai<230,1≤q≤105,0≤L,R<230,op∈{0,1}。
子任务编号 | n , q n,q n,q | a i a_i ai | o p op op |
---|---|---|---|
1 1 1 | ≤ 1 0 2 \le 10^2 ≤102 | < 2 30 < 2^{30} <230 | = 0 =0 =0 |
2 2 2 | ≤ 1 0 2 \le 10^2 ≤102 | < 2 30 < 2^{30} <230 | = 1 =1 =1 |
3 3 3 | ≤ 2 × 1 0 3 \le 2\times 10^3 ≤2×103 | < 2 10 < 2^{10} <210 | = 0 =0 =0 |
4 4 4 | ≤ 2 × 1 0 3 \le 2\times 10^3 ≤2×103 | < 2 10 < 2^{10} <210 | = 1 =1 =1 |
5 5 5 | ≤ 2 × 1 0 3 \le 2\times 10^3 ≤2×103 | < 2 30 < 2^{30} <230 | = 0 =0 =0 |
6 6 6 | ≤ 2 × 1 0 3 \le 2\times 10^3 ≤2×103 | < 2 30 < 2^{30} <230 | = 1 =1 =1 |
7 7 7 | ≤ 1 0 5 \le 10^5 ≤105 | < 2 10 < 2^{10} <210 | = 0 =0 =0 |
8 8 8 | ≤ 1 0 5 \le 10^5 ≤105 | < 2 10 < 2^{10} <210 | = 1 =1 =1 |
9 9 9 | ≤ 1 0 5 \le 10^5 ≤105 | < 2 30 < 2^{30} <230 | = 0 =0 =0 |
10 10 10 | ≤ 1 0 5 \le 10^5 ≤105 | < 2 30 < 2^{30} <230 | = 1 =1 =1 |
题解:
首先可以知道,对于每个固定的左端点,只有最多
l
o
g
log
log 个区间有用,因为对于与和改变的断点后面值相同的区间会包含它,不优。
现在只有
n
l
o
g
n
nlogn
nlogn 的区间。
然后再把包含关系去掉。
现在对于两个相交区间,采取区间差分即可。即新建一个区间,表示同时包含两个区间时贡献去重。
#include<bits/stdc++.h>
#define N 500005
#define A t[p].ls
#define B t[p].rs
using namespace std;
inline int read(){
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
return x*f;
}
int a[N],n;
struct seg{
int ls,rs,sum;
}t[N<<4];
int tot;
inline int add(){
t[++tot].ls=0,t[tot].rs=0,t[tot].sum=0;
return tot;
}
inline void up(int p){
t[p].sum=t[A].sum+t[B].sum;
}
int change(int p,int q,int l,int r,int to,int val){
t[p]=t[q];
if(l==r){
t[p].sum+=val;
return p;
}
int mid=(l+r)>>1;
if(to<=mid)A=change(add(),t[q].ls,l,mid,to,val);
else B=change(add(),t[q].rs,mid+1,r,to,val);
up(p);
return p;
}
int quer(int q,int p,int l,int r,int to){
if(to<=l)return t[p].sum-t[q].sum;
int mid=(l+r)>>1;
int sum=quer(t[q].rs,t[p].rs,mid+1,r,to);
if(to<=mid)sum+=quer(t[q].ls,t[p].ls,l,mid,to);
return sum;
}
int nex[N][31];
struct node{
int l,r,val,ad,b;
inline node(int i=0,int j=0,int k=0,int h=0,int z=0){
l=i,r=j,val=k,ad=h,b=z;
}
}q[N*30*2];
bool cmp1(node a,node b){
if(a.val==b.val){
if(a.l==b.l)return a.r>b.r;
return a.l<b.l;
}
return a.val<b.val;
}
//bool cmp2(node a,node b){if(a.l==b.l)return a.r>b.r;return a.l<b.l;}
bool cmp2(node a,node b){if(a.b==b.b)return a.l<b.l;return a.b<b.b;}
bool cmp3(node a,node b){if(a.b==b.b)return a.r<b.r;return a.b<b.b;}
int root[N],qt;
inline void test(int p){
cout<<q[p].l<<" "<<q[p].r<<" "<<q[p].val<<" "<<q[p].ad<<" "<<q[p].b<<endl;
}
inline void qad(int i,int j,int k,int h,int z){
q[++qt].l=i,q[qt].r=j,q[qt].val=k,q[qt].ad=h,q[qt].b=z;
}
int main(){
// freopen("nowcoder3.in","r",stdin);
// freopen("nowcoder.out","w",stdout);
n=read();int op=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int j=0;j<=30;++j){
nex[n+1][j]=n+1;
for(int i=n;i;--i){
if((a[i]>>j)&1)nex[i][j]=nex[i+1][j];
else nex[i][j]=i;
}
}
for(int i=1;i<=n;++i){
int val=(1ll<<31)-1,k=i,minn=n+1;
for(int j=0;j<=30;++j){
if(!((a[i]>>j)&1))val-=(1<<j);
else minn=min(minn,nex[i][j]);
}
//cout<<i<<":"<<val<<endl;
k=minn;
qad(i,i,val,1,0);
while(k!=n+1&&val){
minn=n+1;
for(int j=0;j<=30;++j){
if((val>>j)&1)if(!((a[k]>>j)&1))val-=1<<j;
if((val>>j)&1)minn=min(minn,nex[k][j]);
}//cout<<k<<" "<<val<<endl;
qad(i,k,val,1,0);
k=minn;
//cout<<i<<" "<<k<<" "<<val<<" "<<qt<<endl;
}
//cout<<endl;
}
//cout<<qt<<endl;
sort(q+1,q+1+qt,cmp1);
int pre=qt;
//cout<<endl;
for(int i=1,j;i<=pre;i=j+1){
for(j=i;j+1<=qt&&(q[j+1].val==q[i].val);++j);
int min_r=n+1;
for(int k=j;k>=i;--k){
if(q[k].r>=min_r)q[k].b=1;
min_r=min(min_r,q[k].r);
}
sort(q+i,q+j+1,cmp2);
for(int k=i+1;k<=j;++k){
if(q[k].b)break;
qad(q[k-1].l,q[k].r,q[k].val,-1,0);
//test(qt);
}
//for(int k=i;k<=j;++k)test(k);
//cout<<endl;
}//cout<<1<<endl;
sort(q+1,q+1+qt,cmp3);
//cout<<qt<<endl;
tot=-1;add();
//cout<<qt<<endl;
//cout<<endl;
for(int i=1,j=1;i<=n;++i){
if(q[j].b)break;
//cout<<i<<":"<<endl;
while(j<=qt&&q[j].r<=i&&q[j].b==0){
if(root[i]){
root[i]=change(add(),root[i],1,n,q[j].l,q[j].ad);
}else{
root[i]=change(add(),root[i-1],1,n,q[j].l,q[j].ad);
}
//cout<<q[j].l<<" "<<q[j].r<<" "<<q[j].ad<<" "<<q[j].val<<endl;
++j;
}
//cout<<i<<endl;
}
//cout<<1<<endl;
int t=read(),la=0;
//cout<<qt<<endl;
//return 0;
while(t--){
int l=read(),r=read();
if(op==0)la=0;
l=(l^la)%n+1,r=(r^la)%n+1;
if(l>r)swap(l,r);
la=quer(root[l-1],root[r],1,n,l);
//cout<<root[l-1]<<" "<<root[r]<<endl;
printf("%d\n",la);
}
//node now(1,1,1,1,1);cout<<now.l<<" "<<now.r<<endl;
return 0;
}
/*
5 1
15 14 13 11 7
1
2 5
*/