专栏文章

XOR and Number Theory 题解

P12828题解参与者 6已保存评论 6

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
6 条
当前快照
1 份
快照标识符
@mipat7f8
此快照首次捕获于
2025/12/03 08:58
3 个月前
此快照最后确认于
2025/12/03 08:58
3 个月前
查看原文
我操,O(3log2m)O(3^{\log_2m}) 彻底怒了。O(3log2m)O(3^{\log_2m}) 指出了最核心的矛盾点:如果 nn 开到 101810^{18}mm 开到 2×1052\times 10^5,或者把时限开到 400ms400\text{ms},怎么可能 O(min(n,m2))O(\sum \min(n,m^2)) 轻轻松松直接通过?这确实是我的严重错误。我需要彻底承认 n,mn,m 开的不够大,或者时限开的不够小,想办法把 DLESS Round 糊弄过去。

做一点说明:n5×107n\le5\times10^7 本来就是给 O(nlogm)O(n\log m) 做法的,但是怕不敢写,所以又给了个 10710^7

首先考察 xy=gcd(x,y)x\oplus y=\gcd(x,y) 的性质。
发现当 y>xy>x 时,yxyxgcd(y,x)y\oplus x\ge y-x\ge \gcd(y,x),所以当 yx=gcd(y,x)y\oplus x=\gcd(y,x) 时,上述三个东西都相等,不妨设它们等于 dd
接下来考察 x2mod(y2xy)x^2\bmod(y^2-xy),设 x=xdx=x'd,则 y=(x+1)dy=(x'+1)d,则:
x2mod(y2xy)=x2mody(yx)=x2d2mod(x+1)d2=(x2mod(x+1))d2=d2\begin{aligned} x^2\bmod(y^2-xy) &= x^2\bmod y(y-x) \\ &= x'^2d^2\bmod (x'+1)d^2 \\ &= (x'^2\bmod (x'+1))d^2 \\ &= d^2 \end{aligned}
事实上,这个无论怎么推都能推出来。
接下来是难点,考虑对所有的 (x,y)(x,y)d2d^2 之和。
d2d^2 貌似并没有太好的性质,不过 d105d\le 10^5,这启发我们可以枚举 dd,并计算 (x,y)(x,y) 的对数,此时我们可以这样简化条件:
  • ddyy 的因数。
  • dd 在二进制下是 yy 的真子集(即二进制下 dd11 的位 yy 这一位也均为 11)。
对于 dd,我们只要求出满足条件的 yy 的个数即可,xx 自然满足条件。
为了方便,对于第二个条件只考虑 ddyy 的子集,最后再减去 i=1mi2=16m(m+1)(2m+1)\sum_{i=1}^mi^2=\frac{1}{6}m(m+1)(2m+1) 即可。
接下来尝试建立子集与因数之间的关系,这看似很难,但是在 d105d\le10^5 的情况下我们只枚举了 dd 本身,貌似还要接着枚举什么。
h=highbit(d)h=\operatorname{highbit}(d),显然 dd 是否是 yy 的子集只跟 yy 的最低 hh 位有关,不妨考虑枚举 yy 的最低 hhpp,此时我们竟能惊人地建立起子集和因数之间的关系:
  • y0(modd)y\equiv 0\pmod{d}
  • yp(mod2h)y\equiv p\pmod{2^h}
EXCRT 求解的个数即可,可能需要预处理逆元做到 O(mlogm+3log2m)O(m\log m+3^{\log_2m}),用神秘的 O(1)O(1) 求模 2m2^m 下的逆元可以做到 O(3log2m)O(3^{\log_2m})
CPP
#include<bits/stdc++.h>
#define cint const int
#define uint unsigned int
#define cuint const unsigned int
#define ll long long
#define cll const long long
#define ull unsigned long long
#define cull const unsigned long long
#define sh short
#define csh const short
#define ush unsigned short
#define cush const unsigned short
using namespace std;
int read()
{
	int x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch-'0');
		ch=getchar();
	}
	return x;
}
void print(cint x)
{
	if(x<10)
	{
		putchar(x+'0');
		return;
	}
	print(x/10);
	putchar(x%10+'0');
}
void princh(cint x,const char ch)
{
	print(x);
	putchar(ch);
}
cint p=1e9+7;
int n,m;
int ans;
int inv[1000001],hb[1<<20|1],chb[1<<20|1];
void init()
{
	cint M=(1<<30)-1;
	for(int i=1;i<=1e6;i+=2)
	{
		int a=i,b=1;
		for(int j=1;j<=22;++j)
		{
			b=((1ll*b*a)&M);
			a=((1ll*a*a)&M);
		}
		inv[i]=b;
	}
	for(int i=1;i<=1<<20;++i)
	{
		hb[i]=max(hb[i-1],i&(-i));
		chb[i]=chb[i-1]+(hb[i]!=hb[i-1]);
	}
}
int calc(cint x,cint y,cint mod)
{
	cll d=((1ll*inv[x]*y)&(mod-1))*x;
	return (d>n?0:(n-d)/(1ll*x*mod)+1);
}
int base;
void solve()
{
	cint M=(1<<chb[m])-1;
	for(int i=1;i<=M;i+=2)
	{
		cint mod=(1<<chb[i]);
		for(int j=i;;j=((j-2)&i))
		{
			if(hb[j]!=hb[i])break;
			if(j>m)continue;
			ans=(ans+1ll*base*j*base*j%p*calc(j,i,mod))%p;
			if(j==1)break;
		}
	}
}
void doit()
{
	n=read();
	m=read();
	base=1;
	ans=-1ll*m*(m+1)*(m<<1|1)/6%p;
	while(m)
	{
		solve();
		base<<=1;
		n>>=1;
		m>>=1;
	}
	princh(ans,'\n');
}
int main()
{
	init();
	int T=read();
	while(T--)doit();
	return 0;
}

评论

6 条评论,欢迎与作者交流。

正在加载评论...