洛谷3794 签到题IV
题目描述
给定一个长度为n的序列$a_1,a_2...a_n$,其中每个数都是正整数。
你需要找出有多少对(i,j),$1 \leq i \leq j \leq n$且$gcd(a_i,a_{i+1}...a_j)~xor~(a_i~or~a_{i+1}~or~...~or~a_j)=k$,其中xor表示二进制异或,or表示二进制或。
输入输出格式
输入格式:
第一行两个整数n、k。
第二行n个整数$a_1,a_2...a_n$。
输出格式:
输出合法的(i,j)的对数。
输入输出样例
输入样例#1: 复制
5 6
2 4 3 4 2
输出样例#1: 复制
8
说明
对于30%的数据,$n \leq 500$。
对于60%的数据,$n \leq 100000$。
对于100%的数据,$1 \leq n,a_i \leq 500000$。
先枚举左端点,显然随着右端点右移,gcd不会增加,or不会减小
而且gcd每次减小最大为原来1/2,所以相同的gcd共可以分成logn块,实际上远远达不到
还有一个性质a^b^a=b
所以gcd^or^gcd=k^gcd=or
这样对于gcd相同的区间,用二分求出符合条件的or数量
用ST表维护x~y的gcd和or,而且了log要预处理,这样会快一些
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 typedef long long lol; 8 int GCD[500001][21],OR[500001][21],Log[500001],n,k; 9 lol ans; 10 int gcd(int a,int b) 11 { 12 if (!b) return a; 13 return gcd(b,a%b); 14 } 15 int getg(int x,int y) 16 { 17 int d=Log[(y-x+1)]; 18 return gcd(GCD[x][d],GCD[y-(1<<d)+1][d]); 19 } 20 int getor(int x,int y) 21 { 22 int d=Log[(y-x+1)]; 23 return OR[x][d]|OR[y-(1<<d)+1][d]; 24 } 25 int find(int x,int l,int g) 26 { 27 int r=n,as=l; 28 while (l<=r) 29 { 30 int mid=(l+r)/2; 31 int G=getg(x,mid); 32 if (G==g) as=mid,l=mid+1; 33 else r=mid-1; 34 } 35 return as; 36 } 37 void query(int d,int x,int l,int r) 38 { 39 int L=l,R=r,as1=0,as2=-1; 40 while (l<=r) 41 { 42 int mid=(l+r)/2; 43 int o=getor(x,mid); 44 if (o==d) as1=mid,r=mid-1; 45 if (o<d) l=mid+1; 46 if (o>d) r=mid-1; 47 } 48 while (L<=R) 49 { 50 int mid=(L+R)/2; 51 int o=getor(x,mid); 52 if (o==d) as2=mid,L=mid+1; 53 if (o<d) L=mid+1; 54 if (o>d) R=mid-1; 55 } 56 ans+=as2-as1+1; 57 } 58 int main() 59 {int i,x,pos,j; 60 cin>>n>>k; 61 for (i=1;i<=n;i++) 62 { 63 scanf("%d",&x); 64 GCD[i][0]=x; 65 OR[i][0]=x; 66 } 67 for (i=2;i<=n;i++) 68 Log[i]=Log[i/2]+1; 69 for (i=1;i<=20;i++) 70 { 71 for (j=1;j<=n;j++) 72 if (j+(1<<i)-1<=n) 73 { 74 GCD[j][i]=gcd(GCD[j][i-1],GCD[j+(1<<i-1)][i-1]); 75 OR[j][i]=OR[j][i-1]|OR[j+(1<<i-1)][i-1]; 76 } 77 } 78 for (i=1;i<=n;i++) 79 { 80 for (j=i;j<=n;j=pos+1) 81 { 82 int g=getg(i,j); 83 pos=find(i,j,g); 84 query(g^k,i,j,pos); 85 } 86 } 87 cout<<ans; 88 }