【JZOJ5894】【NOIP2018模擬10.5】同餘方程(容斥+計數問題+類數位DP)
阿新 • • 發佈:2018-12-13
Problem
Hint
Solution
- 首先,考慮類似差分的容斥。
- 設表示x在[0,a-1]範圍內,y在[0,b-1]範圍內的答案。則原。
- 問題轉化為求解。
- 我們列舉一個i,表示x在(二進位制)第i位比a小了。亦即a的第i位=1,而x的第i為=0;而x的前i-1位均與a同。這樣,x後面的位就可以亂填了。
- 同時列舉一個j,表示y在第j位比b小了。
- 這樣的話,a、b就會分成如下三段:
- 如圖,藍線以左為已知,兩線間為任意,綠線以右為任意2。
- 假設,那麼若確定了z的任意段,就確定了x的任意段。因為y的任意段是已知的。也就是說,對於同一z,任意段只有1組方案。
- 但是,x和y的任意2段均不確定。假設列舉y的任意2段(設任意2段長度為l2,則從0列舉到),就可以確定x的任意2段了。因此,對於同一z,任意2段有組方案。
- 那麼,假設確定了z,兩個任意段就有組方案。
- 但是,我們還要使。
- 設任意段長為l1,則z的取值範圍是。
- 我們設已知段的異或和為p,則的取值範圍是。
- 求出其中有tot個數是m的倍數,那麼合法的z有tot個。令。
- 時間複雜度:。
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);
}