Description

给出[JZOJ5894] 【NOIP2018模拟10.5】同余方程_二维,求有多少组(x,y),满足[JZOJ5894] 【NOIP2018模拟10.5】同余方程_数位DP_02
[JZOJ5894] 【NOIP2018模拟10.5】同余方程_数学_03
其中一档部分分 [JZOJ5894] 【NOIP2018模拟10.5】同余方程_数位DP_04

Solution

先从部分分入手,考虑l1=r1怎么做
首先肯定是拆成[JZOJ5894] 【NOIP2018模拟10.5】同余方程_二维_05[JZOJ5894] 【NOIP2018模拟10.5】同余方程_数学_06两部分来做(二维类似二维前缀和一样拆)

我们可以枚举一个i,表示y的前i-1位是和上界相同,第i位小于上界,那后面就可以随便选了,x的后面位置是没有用的,因为无论我们需要什么,我们都可以通过改变y来使得它异或成我们需要的,并且是唯一对应的。

现在问题变成y从i+1位开始可以随便选,k可以随便选,要满足[JZOJ5894] 【NOIP2018模拟10.5】同余方程_#define_07
既然y从i+1位可以随便选,也就是说k*m要满足前i位等于x xor y的前i位
这样的k显然是一个区间,直接上界下界除一下再减就算出来了

现在回归原题,x也是可变的
其实思路是一样的,我们再枚举x的前j位与上界相同,第j位小于上界
考虑x xor y,前min(i,j)位是两个都确定,min(i,j)+1到max(i,j)位是确定一个,这部分和前面是一样的,后面的位两个都不确定,相当于无论x后面怎么选,都能通过改变y来达到,因此只需要将第一部分的答案乘上2^(后面的位数)即可。

注意我们这样算出来其实上界是r-1的(因为我们每一位都保证小于上界)
因此实际上做的时候要把上界+1
复杂度[JZOJ5894] 【NOIP2018模拟10.5】同余方程_#include_08

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#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 LL long long
#define mo 998244353
using namespace std;
LL l1,r1,l2,r2,m,cf[61];
LL get(LL m1,LL m2)
{
LL s=0;
fod(i,59,0)
{
if(m1&cf[i])
fod(j,59,0)
{
if(m2&cf[j])
{
int c=max(i,j);
LL v=((m1^m2^((i==j)?0:cf[c]))|(cf[c]-1))^(cf[c]-1);
if(v==0) s=(s+((cf[c]-1)/m+1)%mo*(cf[min(i,j)]%mo)%mo)%mo;
else s=(s+(((v+cf[c]-1)/m-(v-1)/m)%mo+mo)%mo*(cf[min(i,j)]%mo)%mo)%mo;
}
}
}

return s;
}
int main()
{
cin>>l1>>r1>>l2>>r2>>m;
LL s=0;
cf[0]=1;
fo(i,1,60) cf[i]=cf[i-1]*(LL)2;
printf("%lld\n",(get(r1+1,r2+1)-get(l1,r2+1)-get(r1+1,l2)+get(l1,l2)+mo+mo)%mo);
}