天天看点

jzoj5894. 【NOIP2018模拟10.5】同余方程题目描述30%60%100%code

题目描述

jzoj5894. 【NOIP2018模拟10.5】同余方程题目描述30%60%100%code

30%

直接暴力搞

60%

可以打个表找规律,发现大致可以分成log段连续的数

然后随便搞

100%

考虑用容斥的思想,把询问拆成四个

所以就变成了求

a n s ( l , r ) = ∑ i = 0 l ∑ j = 0 r ( i ⊕ j ) ≡ 0    ( m o d    m ) ans(l,r)=\sum_{i=0}^{l}{\sum_{j=0}^{r}{(i⊕j)≡0\;(mod \; m)}} ans(l,r)=∑i=0l​∑j=0r​(i⊕j)≡0(modm)

显然如果直接枚举还是会挂,考虑枚举i(j)中第一个与l(r)不同的位(前提是i≤l,j≤r)

jzoj5894. 【NOIP2018模拟10.5】同余方程题目描述30%60%100%code

(假设l不同的位比r后)

那么用红框表示已知部分,蓝框表示未知部分

jzoj5894. 【NOIP2018模拟10.5】同余方程题目描述30%60%100%code

所以异或之后就会变成这样

jzoj5894. 【NOIP2018模拟10.5】同余方程题目描述30%60%100%code

中间的紫色部分表示一半已知,一半未知,后面的表示完全未知

左边的部分可以直接l和r异或得出(要考虑末尾i/j不同时,那一位要取反,除非i=j)

显然未知部分的所有情况都会被异或出来

因为 a ⊕ b = c a⊕b=c a⊕b=c,而中间已知a,所以每个c只对应一个b

而后面部分a和b都不知道,所以每个c会出现有2^(蓝色部分长度)次

所以每次的贡献就是

((红色部分,后面的所有情况)的贡献)*2^(蓝色部分长度)

中间的贡献可以直接求

最后考虑i=l、j=r的情况,最终答案就是

a n s ( r 1 , r 2 ) − a n s ( l 1 − 1 , r 2 ) − a n s ( r 1 , l 2 − 1 ) + a n s ( l 1 − 1 , l 2 − 1 ) ans(r1,r2)-ans(l1-1,r2)-ans(r1,l2-1)+ans(l1-1,l2-1) ans(r1,r2)−ans(l1−1,r2)−ans(r1,l2−1)+ans(l1−1,l2−1)

code

#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define mod 998244353
using namespace std;

bool a[61];
bool b[61];
long long p[61];
long long P[61];
long long l1,r1,l2,r2,m,A,B;

long long get(long long l,long long r)
{
	if (l>r) return 0;
	if (l)
	return (r/m-(l-1)/m)%mod;
	else
	return (r/m+1)%mod;//要考虑0
}

long long ans(long long l,long long r)
{
	int i,j,mx;
	long long L=l,R=r,Ans=0,S=l^r;
	
	A=-1;
	B=-1;
	while (l)
	{
		a[++A]=l&1;
		l>>=1;
	}
	while (r)
	{
		b[++B]=r&1;
		r>>=1;
	}
	
	fo(i,0,A)
	if (a[i])
	Ans=(Ans+get(((S/p[i])*p[i])^p[i],((S/p[i])*p[i])^p[i]+p[i]-1))%mod;//i=l的情况
	fo(i,0,B)
	if (b[i])
	Ans=(Ans+get(((S/p[i])*p[i])^p[i],((S/p[i])*p[i])^p[i]+p[i]-1))%mod;//j=r的情况
	
	fo(i,0,A)
	if (a[i])
	{
		fo(j,0,B)
		if (b[j])
		{
			mx=max(i,j);
			
			if (i!=j)//特判i=j
			Ans=(Ans+get(((S/p[mx])*p[mx])^p[mx],((S/p[mx])*p[mx])^p[mx]+p[mx]-1)*P[min(i,j)])%mod;
			else
			Ans=(Ans+get(((S/p[mx])*p[mx]),((S/p[mx])*p[mx])+p[mx]-1)*P[min(i,j)])%mod;
		}
	}
	
	Ans+=((S%m)==0);//当i=l且j=r时
	return Ans;
}

void init()
{
	int i;
	
	p[0]=1;
	P[0]=1;
	fo(i,1,60)
	{
		p[i]=(p[i-1]<<1);
		P[i]=p[i]%mod;
	}
}

int main()
{
	freopen("mod.in","r",stdin);
	freopen("mod.out","w",stdout);
	
	init();
	
	scanf("%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&m);
	printf("%lld\n",((ans(r1,r2)-ans(l1-1,r2)-ans(r1,l2-1)+ans(l1-1,l2-1))%mod+mod)%mod);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}