题解:AT_abc138_f [ABC138F] Coincidence
Lv5_Railgun · · 题解
为什么大家写的都是记忆化搜索,没人写正向递推()
原题传送门
看到数据范围,考虑
考虑将
可以发现,对于一位的二进制,当
我们可以利用数位 dp 解决该问题。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int dp[66][2][2][2];//dp[i][j][k][l]为,当前处理第i位,x取顶的状态是i,y取顶的状态是j,x,y是否都已取值的状态为l
int l,r;
int cal(int x,int y){
for(int i=0;i<=60;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) for(int l=0;l<2;l++) dp[i][j][k][l]=0;
dp[60][1][1][0]=1;
for(int i=59;i>=0;i--){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
for(int l=0;l<2;l++){
bool nowj,nowk;
if(j==1&&!((x>>i)&1)){
nowj=1;
}
else nowj=0;
if(k==1&&!((y>>i)&1)){
nowk=1;
}
else nowk=0;
dp[i][nowj][nowk][l]=(dp[i][nowj][nowk][l]+dp[i+1][j][k][l])%mod;
if(nowj==0&&nowk==0) dp[i][j][k][1]=(dp[i][j][k][1]+dp[i+1][j][k][l])%mod;
if(nowj==0&&l==1) dp[i][j][nowk][l]=(dp[i][j][nowk][l]+dp[i+1][j][k][l])%mod;
}
}
}
}
return dp[0][0][0][1]+dp[0][0][1][1]+dp[0][1][0][1]+dp[0][1][1][1];
}
signed main(){
cin>>l>>r;
int add=cal(r,r)%mod,add2=cal(l-1,r)%mod,add3=cal(l-1,l-1)%mod,add4=cal(r,l-1)%mod;
cout<<(add-add2+add3-add4+mod)%mod<<endl;//做二维差分,得出答案
}