专栏文章
XOR and Number Theory 题解
P12828题解参与者 6已保存评论 6
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 6 条
- 当前快照
- 1 份
- 快照标识符
- @mipat7f8
- 此快照首次捕获于
- 2025/12/03 08:58 3 个月前
- 此快照最后确认于
- 2025/12/03 08:58 3 个月前
我操, 彻底怒了。 指出了最核心的矛盾点:如果 开到 , 开到 ,或者把时限开到 ,怎么可能 轻轻松松直接通过?这确实是我的严重错误。我需要彻底承认 开的不够大,或者时限开的不够小,想办法把 DLESS Round 糊弄过去。
做一点说明: 本来就是给 做法的,但是怕不敢写,所以又给了个 。
首先考察 的性质。
发现当 时,,所以当 时,上述三个东西都相等,不妨设它们等于 。
接下来考察 ,设 ,则 ,则:
事实上,这个无论怎么推都能推出来。
接下来是难点,考虑对所有的 求 之和。
貌似并没有太好的性质,不过 ,这启发我们可以枚举 ,并计算 的对数,此时我们可以这样简化条件:
- 是 的因数。
- 在二进制下是 的真子集(即二进制下 为 的位 这一位也均为 )。
对于 ,我们只要求出满足条件的 的个数即可, 自然满足条件。
为了方便,对于第二个条件只考虑 是 的子集,最后再减去 即可。
接下来尝试建立子集与因数之间的关系,这看似很难,但是在 的情况下我们只枚举了 本身,貌似还要接着枚举什么。
设 ,显然 是否是 的子集只跟 的最低 位有关,不妨考虑枚举 的最低 位 ,此时我们竟能惊人地建立起子集和因数之间的关系:
EXCRT 求解的个数即可,可能需要预处理逆元做到 ,用神秘的 求模 下的逆元可以做到 。
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 条评论,欢迎与作者交流。
正在加载评论...