Problem
Hint
Solution
首先,考虑类似差分的容斥。 设
f
a
,
b
f_{a,b}
f a , b 表示x在[0,a-1]范围内,y在[0,b-1]范围内的答案。则原
A
n
s
=
f
r
1
+
1
,
r
2
+
1
−
f
l
1
,
r
2
+
1
−
f
r
1
+
1
,
l
2
+
f
l
1
,
l
2
Ans=f_{r_1+1,r_2+1}-f_{l_1,r_2+1}-f_{r_1+1,l_2}+f_{l_1,l_2}
A n s = f r 1 + 1 , r 2 + 1 − f l 1 , r 2 + 1 − f r 1 + 1 , l 2 + f l 1 , l 2 。 问题转化为求解
f
a
,
b
f_{a,b}
f a , b 。
我们枚举一个i,表示x在(二进制)第i位比a小了。亦即a的第i位=1,而x的第i为=0;而x的前i-1位均与a同。这样,x后面的位就可以乱填了。 同时枚举一个j,表示y在第j位比b小了。 这样的话,a、b就会分成如下三段: 如图,蓝线以左为已知,两线间为任意,绿线以右为任意2。
假设
x
⊕
y
=
z
x\oplus y=z
x ⊕ y = z ,那么若确定了z的任意段,就确定了x的任意段。因为y的任意段是已知的。也就是说,对于同一z,任意段只有1组方案。 但是,x和y的任意2段均不确定。假设枚举y的任意2段(设任意2段长度为l2,则从0枚举到
2
l
2
−
1
2^{l2}-1
2 l 2 − 1 ),就可以确定x的任意2段了。因此,对于同一z,任意2段有
2
l
2
2^{l2}
2 l 2 组方案。 那么,假设确定了z,两个任意段就有
1
∗
2
l
2
=
2
l
2
1*2^{l2}=2^{l2}
1 ∗ 2 l 2 = 2 l 2 组方案。
但是,我们还要使
m
∣
z
m|z
m ∣ z 。 设任意段长为l1,则z的取值范围是
[
0
,
2
l
1
+
l
2
−
1
]
[0,2^{l1+l2}-1]
[ 0 , 2 l 1 + l 2 − 1 ] 。 我们设已知段的异或和为p,则
x
⊕
y
x\oplus y
x ⊕ y 的取值范围是
[
p
,
p
+
2
l
1
+
l
2
−
1
]
[p,p+2^{l1+l2}-1]
[ p , p + 2 l 1 + l 2 − 1 ] 。 求出其中有tot个数是m的倍数,那么合法的z有tot个。令
a
n
s
+
=
t
o
t
∗
2
l
2
ans+=tot*2^{l2}
a n s + = t o t ∗ 2 l 2 。
时间复杂度:
O
(
l
o
g
2
2
1
0
18
)
≈
O
(
6
0
2
)
O(log_2^210^{18})≈O(60^2)
O ( l o g 2 2 1 0 1 8 ) ≈ O ( 6 0 2 ) 。
Code
#include <bits/stdc++.h>
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const ll mo= 998244353 , p59= 1ll << 59 ;
ll l1, r1, l2, r2, m, i, j, x, pa, y, pb, L1, L2, L3, p, p1, tot;
ll dp ( ll a, ll b)
{
x= p59; pa= 0 ; ll ans= 0 ;
fd ( i, 59 , 0 )
{
pa<<= 1 ;
if ( x& a)
{
y= p59; pb= 0 ;
fd ( j, 59 , 0 )
{
pb<<= 1 ;
if ( y& b)
{
L1= 59 - max ( i, j) ; L2= abs ( i- j) ; L3= min ( i, j) ;
p= ( i> j ? pa^ ( pb>> L2) : pb^ ( pa>> L2) ) << L2+ L3;
p1= p+ ( 1ll << L2+ L3) - 1 ;
tot= ( p1/ m - p/ m + ( p% m== 0 ) ) % mo;
( ans+ = tot* ( ( 1ll << L3) % mo) ) % = mo;
}
pb+ = ( bool ) ( y& b) ; y>>= 1 ;
}
}
pa+ = ( bool ) ( x& a) ; x>>= 1 ;
}
return ans;
}
int main ( )
{
freopen ( "mod.in" , "r" , stdin ) ;
freopen ( "mod.out" , "w" , stdout ) ;
scanf ( "%lld%lld%lld%lld%lld" , & l1, & r1, & l2, & r2, & m) ;
printf ( "%lld" , ( dp ( r1+ 1 , r2+ 1 ) - dp ( l1, r2+ 1 ) - dp ( r1+ 1 , l2) + dp ( l1, l2) + 2 * mo) % mo) ;
}