洛谷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 }

 

posted @ 2018-01-26 15:23  Z-Y-Y-S  阅读(270)  评论(1编辑  收藏  举报