【JZOJ 5894】【NOIP2018模拟10.5】同余方程

版权声明:本文为蒟蒻所写,神犇转载尽情拍打喂食虐待,如发现任何的辣鸡错误欢迎吐槽! https://blog.csdn.net/HOWARLI/article/details/82946718

Description

在这里插入图片描述

Solution

把题目容斥一下,
假设当前求x在0 ~ l1中和y在0~ l2中的答案,

显然的,当x,y的取值均为2的次方时,答案是很好求的,
考虑怎么转成这样:
那么我们枚举l1的一位为1的二进制i,枚举l2的一位为1的二进制j,
我们使得x的前i-1位为二进制跟l1相同,第i位为0,那么x剩下二进制位的取值就自由了,也就是0 ~ 2 i 2^i
y也同理,那么我们就成功吧题目转成了x,y均为2的次方的情况,

复杂度: O ( l o g ( n ) 2 ) O(log(n)^2)

Code

#include <cstdio>
#include <algorithm>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=100500,mo=998244353;
int read(int &n)
{
	char ch=' ';int q=0,w=1;
	for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
	if(ch=='-')w=-1,ch=getchar();
	for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
LL ans;
LL l1,r1,L1,R1,M;
LL er[100];
LL doit(LL n,LL m)
{
	n=max(n,0);m=max(m,0);
	LL ans=0;
	fod(i,62,1)if(er[i]&n)
	{
		fod(j,62,1)if(er[j]&m)
		{
			LL t=((n&(er[63]-1-er[i+1]+1))^(m&(er[63]-1-er[j+1]+1)))&(er[63]-1-er[max(i,j)]+1);
			ans=(ans+er[min(i,j)]%mo*(((t+er[max(i,j)]-1)/M-(max(t,1)-1)/M+(t==0))%mo))%mo;
		}
	}
	fod(i,62,1)if(er[i]&n)
	{
		LL l=((n&(er[63]-1-er[i+1]+1))^m)&(er[63]-1-er[i]+1);
		LL r=l|(er[i]-1);
		ans=(ans-((l-1)/M)+r/M)%mo;
		if(l==0)++ans;
	}
	fod(i,62,1)if(er[i]&m)
	{
		LL l=(n^(m&(er[63]-1-er[i+1]+1)))&(er[63]-1-er[i]+1);
		LL r=l|(er[i]-1);
		ans=(ans-((l-1)/M)+r/M)%mo;
		if(l==0)++ans;
	}
	if((n^m)%M==0)++ans;
	return ans;
} 
int main()
{
	freopen("mod.in","r",stdin);
	freopen("mod.out","w",stdout);
	int q,w;
	scanf("%lld%lld%lld%lld%lld",&l1,&r1,&L1,&R1,&M);
	er[1]=1;fo(i,2,63)er[i]=er[i-1]<<1;
	
	ans=doit(r1,R1)-doit(l1-1,R1)-doit(r1,L1-1)+doit(l1-1,L1-1);
	printf("%lld\n",(ans%mo+mo)%mo);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/HOWARLI/article/details/82946718