LOJ6231. GCD & XOR
很好的题目。
首先,\(\gcd\) 有个很好的性质:
对于一列数组,从左往右取前缀 \(\gcd\),不同的值最多只有 \(\log w\) 种。
我的yy证明:
对于 a[1],它最多为 \(\log w\) 个质因子相乘(全取2),而每向后扫一个数,质因子数要么不变,要么减一,所以至多有 \(\log w\) 个,所以有很多 \(\gcd\) 是相同的。
而且 \(\gcd\) 是满足结合律的,所以很好预处理。
所以我们可以倍增预处理 \(\gcd\) ,然后开始扫,然后倍增跳,然后在找符合的 \(\text{xor}\) 值。
时间复杂度:\(O(n\log^2 n)\)
PS:map的小用法:map很适合这种查找的工作
插入 m.insert(make_pair()) \(O(\log n)\)
或直接用数组复制 m[key]=value... \(O(\log n)\)
然后每次调用 m[key] 时,若不存在则会新建一个二元组 (key,zero),本题中就是这样使用的。(zero 是一个广义的零值)。
然后删除 m.erase(it) 或 m.erase(make_pair()) \(O(\log n)\)
迭代器:用法同 set
empty,clear,size,begin,end同set \(O(1)\)
find(key):查找 key 值为 x 的二元组,若不存在则返回 m.end() \(O(\log n)\)
然后对于 map 里的每一个元素 x,x->first 表示 key 值,x->second 表示 value。
当然 map 里也是可以用 lower_bound(key) 返回的是 map 里的一个元素。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+7;
template <class I>
inline void read(I &x){
int f=1;
char c;
for(c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+(c&15),c=getchar());
x*=f;
}
int n;
ll a[N],f[N][19],K,jc[19],xr[N];
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
map <ll,vector<int> > mp;
map <ll,vector<int> >::iterator it;
vector <int>::iterator vit;
inline void init(){
jc[0]=1;
for(int i=1;i<19;i++) jc[i]=jc[i-1]<<1;
for(int i=1;i<=n;i++) f[i][0]=a[i];
for(int k=1;k<19;k++)
for(int i=1;i+jc[k]-1<=n;i++)
f[i][k]=gcd(f[i][k-1],f[i+jc[k-1]][k-1]);
for(int i=1;i<=n;i++)
xr[i]=xr[i-1]^a[i],mp[xr[i]].push_back(i);
}
int main(){
//freopen("sequence.in","r",stdin);
//freopen("sequence.out","w",stdout);
read(n);
for(int i=1;i<=n;i++)
read(a[i]);
read(K);
init();
for(int l=1;l<=n;l++){
ll gd=a[l];
for(int i=l;i<=n;i++){
gd=gcd(a[i],gd);
int r=i;
for(int k=18;k>=0;k--){
if(r+jc[k]-1<=n&&(f[r][k]%gd==0)) r+=jc[k]-1;
}
if(K%gd) {
i=r;
continue;
}
it=mp.find((K/gd)^xr[l-1]);
if(it==mp.end()) {
i=r;
continue;}
vit=lower_bound((it->second).begin(),(it->second).end(),l);
if(vit==(it->second).end()||*vit>r){
i=r;
continue;
}
printf("%d %d\n",l,*vit);
return 0;
}
}
puts("no solution");
return 0;
}