本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
【CCPC】2022威海站 G. Grade 2 | 数学、循环节
题目链接
Problem - G - Codeforces
题目

题目大意
对于给定的正整数 x,有 n 组询问,每组询问要求对于给定的 l 和 r 回答:
k=l∑r[gcd(kx⊕x,x)=1]
即求有多少个正整数 k 满足 l≤k≤r,且 k×x 与 x 进行异或运算后,取得的结果与 x 的最大公约数是 1。
思路
显然
k=l∑r[gcd(kx⊕x,x)=1]
可以转化为
k=0∑r[gcd(kx⊕x,x)=1]−k=0∑l[gcd(kx⊕x,x)=1]
令 solve(R) 表示 ∑k=0R[gcd(kx⊕x,x)=1],考虑怎样求 solve(R)。
因为 a⊕b=a+b−(a&b),而 x∣kx,所以 gcd(kx⊕x,x)=gcd(kx&x,x)。这说明 gcd(kx⊕x,x) 的值只与 kx 的后 ⌈log2(x)⌉ 个二进制位有关。即
gcd(kx⊕x,x)=gcd((kx)mod2⌈log2(x)⌉⊕x,x)=gcd((kmod2⌈log2(x)⌉×xmod2⌈log2(x)⌉)⊕x,x)=gcd((kmod2⌈log2(x)⌉×x)⊕x,x)
所以令 f(k) 表示 gcd(kx⊕x,x),则 f(k) 具有循环节,为 2⌈log2(x)⌉。
我们只需要先暴力的求出一个循环节内 f(k)=1 的 k 的个数,并对于满足 1≤j≤2⌈log2(x)⌉ 的正整数 j 预处理出 1 到 j 里合法的 k 的数量为 gdj,就可以 O(1) 的计算
solve(R)=⌊2⌈log2(x)⌉R⌋×gd2⌈log2(x)⌉+gdRmod2⌈log2(x)⌉
对于给定的 l 和 r 输出 solve(r)−solve(l−1) 即可。
代码
#include <algorithm>
#include <stdio.h>
using namespace std;
const int N=1048577;
using LL=long long;
int n,x,cnt;
int gd[N];
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
LL solve(LL R)
{
return R/cnt*gd[cnt]+gd[R%cnt];
}
int main()
{
scanf("%d%d",&x,&n);
for (int i=x;i;i>>=1) cnt++;
cnt=1<<cnt;
for (LL i=1;i<=cnt;++i)
gd[i]=gd[i-1]+(gcd(i*x&x,x)==1);
while (n--)
{
LL l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}