【牛客提高训练营5A】同余方程
吉老师的题做不动啊
首先[l1,r1],[l2,r2]并不是非常好做,我们考虑将其拆成前缀信息
设solve(n,m)=\sum_{i=0}^n\sum_{j=0}^m[m|(i\bigoplus j)]
于是我们的答案就变成了solve(r_1,r_2)-solve(l_1-1,r_2)-solve(r_1,l_2-1)+solve(l_1-1,l_2-1)
考虑solve(r_1,r_2)怎么求
一个非常特殊的情况是r_1=2^n-1,r_2=2^m-1,不妨假设n<m,则[0,2^n)和[0,2^m)各选择一个数异或起来,能取遍[0,2^m),且每一个数出现的次数都是2^n
正确性显然
考虑推广到更一般的情况,我们把[0,r_1)拆分一下,拆分成\log段[v,v+2^k)的区间,比如说对于101010,可以拆成[0,2^5),[2^5,2^5+2^3),[2^5+2^3,2^5+2^3+2^1)
这样的拆分有一个特点,如果有v\neq 0,那么一定会存在v>2^k,这个性质接下来非常重要
将[0,r_1),[0,r_2)各拆成\log段区间后,我们暴力从两边各选一段区间出来,假设为[x,x+2^a)和[y,y+2^b),还是不妨假设a<b
于是在忽略x,y的情况下两个区间变成了[0,2^a),[0,2^b),于是各选一个异或起来能取遍[0,2^b)且每个值能被异或出来2^a次
现在考虑把x,y引入,不难发现因为x>2^a,所以从[0,2^a)拿出一个数,加上x和异或x是等价的;y那边同理
于是[0,2^b)中的每一个数拿出来和x\bigoplus y异或一下,就是真实的从[x,x+2^a)和[y,y+2^b)各拿一个数出来异或的结果。
所以现在只需要求出[0,2^b)内有多少个满足异或x\bigoplus y后\rm mod\ m=0,这样的数的个数乘上2^a就是答案了。
做到这里就不会了,接下来都是祖特教我的。
我们不难发现x\bigoplus y如果不是0,则必然大于2^b,于是x\bigoplus y和[0,2^b)内的数异或,必然不会改变必2^b更高的二进制位。
所以想要使得异或出来的数是m的倍数,只需要让x\bigoplus y小于2^b的位数从全0取到全1,从中选出m的倍数即可。
代码
#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int mod=998244353;
inline int dqm(int x) {return x<0?x+mod:x;}
inline int qm(int x) {return x>=mod?x-mod:x;}
LL l1,l2,r1,r2;int m,top[2];
struct Seg{LL v,k;}a[2][65];
inline LL getid(LL a,LL b) {return a%b==0?a/b:a/b+1;}
inline LL solve(LL n,LL k)
{
LL t=0,tot=0;
for(re LL i=63;i>=0;i--)
{
t|=(1ll<<i);
if(!(n&(1LL<<i))) continue;
LL l=k&t,r=l+(1ll<<i)-1;
LL L=getid(l,m),R=r/m;
tot=qm(tot+(R-L+1)%mod);
}
return tot;
}
inline int calc(LL n,LL m) {
++n,++m;int ans=0;
top[0]=top[1]=0;
LL now=0;
for(re LL i=63;i>=0;--i)
if(n>>i&1ll) {
a[0][++top[0]].v=now,a[0][top[0]].k=i;
now|=(1ll<<i);
}
now=0;
for(re LL i=63;i>=0;--i)
if(m>>i&1ll) {
a[1][++top[1]].v=now,a[1][top[1]].k=i;
now|=(1ll<<i);
}
for(re int i=1;i<=top[0];++i)
for(re int j=1;j<=top[1];++j) {
now=a[0][i].v^a[1][j].v;
LL mx=max(a[0][i].k,a[1][j].k),mn=min(a[0][i].k,a[1][j].k);
mn=(1ll<<mn);mn%=mod;
ans=qm(ans+1ll*solve(1ll<<mx,now)%mod*mn%mod);
}
return ans;
}
int main() {
scanf("%lld%lld%lld%lld%d",&l1,&r1,&l2,&r2,&m);
printf("%d\n",dqm(qm(calc(r1,r2)+calc(l1-1,l2-1))-qm(calc(l1-1,r2)+calc(r1,l2-1))));
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· 本地部署 DeepSeek:小白也能轻松搞定!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 从 Windows Forms 到微服务的经验教训
· 李飞飞的50美金比肩DeepSeek把CEO忽悠瘸了,倒霉的却是程序员
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee