傳送門
 
文章目錄
 
題意:
 
求sumsumsum。
 
 a,b,c,d,e≤1e18a,b,c,d,e\le1e18a,b,c,d,e≤1e18
 
思路:
 
這是一篇無從考究的題解,因為fzu現在進不去。
 看到這種題直接考慮數位dpdpdp,對于[A,B],[C,D][A,B],[C,D][A,B],[C,D]兩個區間我們不太好直接處理,但是我們可以容斥一下,即[0,B][0,D]?[0,A?1][0,D]?[0,B][0,C?1]+[0,A?1][0,C?1][0,B][0,D]-[0,A-1][0,D]-[0,B][0,C-1]+[0,A-1][0,C-1][0,B][0,D]?[0,A?1][0,D]?[0,B][0,C?1]+[0,A?1][0,C?1]。
 假設我們求的[0,B][0,D][0,B][0,D][0,B][0,D],我們設計狀態f[pos][flag1][flag2][flag3]f[pos][flag1][flag2][flag3]f[pos][flag1][flag2][flag3]
 (1)flag1(1)flag1(1)flag1表示i<Bi<Bi<B。
 (2)flag2(2)flag2(2)flag2表示j<Dj<Dj<D。
 (3)flag3(3)flag3(3)flag3表示(ixorj)>E(i \ \ xor \ \ j) >E(i??xor??j)>E
 到目前為止,如果這個題改成求方案數,就可以直接秒了,但是改不得。
 設dp1(pos)dp1(pos)dp1(pos)為從pospospos位開始的方案數,dp2(pos)dp2(pos)dp2(pos)為從pospospos位開始的貢獻,考慮如何求貢獻,我們直接按位來考慮,假設當前到了第pospospos位,且當前位(ixorj)==1(i \ \ xor \ \ j)==1(i??xor??j)==1,那么當前位的貢獻就是(1ll<<pos)?dp1(pos?1)+dp2(pos?1)(1ll<<pos)*dp1(pos-1)+dp2(pos-1)(1ll<<pos)?dp1(pos?1)+dp2(pos?1),這個顯然可以維護一個pairpairpair進行轉移。
 所以還是一個裸的數位dpdpdp。
 代碼也比較好寫辣,一定要注意取模,比如代碼686868行,1ll<<pos1ll<<pos1ll<<pos一定要取模,不然炸LLLLLL了,因為這個對拍的時候一直過不了大樣例。。。
 
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<LL
,LL
> PII
;const int N
=110,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;LL a
,b
,c
,d
,e
;
int A
[N
],B
[N
],E
[N
];
PII f
[70][2][2][2];PII 
dp(int pos
,int flag1
,int flag2
,int flag3
) {if(pos
==-1) return {flag3
,0};if(f
[pos
][flag1
][flag2
][flag3
].X
!=-1) return f
[pos
][flag1
][flag2
][flag3
];int x
=flag1
? 1:A
[pos
];int y
=flag2
? 1:B
[pos
];int z
=flag3
? 0:E
[pos
];PII ans
={0,0};for(int i
=0;i
<=x
;i
++) {for(int j
=0;j
<=y
;j
++) {if((i
^j
)<z
) continue;PII now
=dp(pos
-1,flag1
||i
<x
,flag2
||j
<y
,flag3
||((i
^j
)>z
));ans
.X
+=now
.X
; ans
.X
%=mod
;ans
.Y
+=now
.Y
;if((i
^j
)==1) ans
.Y
+=(1ll*(1ll<<pos
)%mod
)*now
.X
%mod
;ans
.Y
%=mod
;}}return f
[pos
][flag1
][flag2
][flag3
]=ans
;
}LL 
solve(LL x
,LL y
) {if(x
<=0||y
<=0) return 0;for(int i
=62;i
>=0;i
--) {A
[i
]=x
>>i
&1;B
[i
]=y
>>i
&1;}memset(f
,-1,sizeof(f
));return dp(62,0,0,0).Y
%mod
;
}int main()
{
int _
; scanf("%d",&_
);for(int __
=1;__
<=_
;__
++) {scanf("%lld%lld%lld%lld%lld",&a
,&b
,&c
,&d
,&e
);for(int i
=62;i
>=0;i
--) E
[i
]=e
>>i
&1;LL ans
=solve(b
,d
)%mod
; ans
-=solve(a
-1,d
); ans
%=mod
; ans
+=mod
; ans
%=mod
;ans
-=solve(b
,c
-1); ans
%=mod
; ans
+=mod
; ans
%=mod
;ans
+=solve(a
-1,c
-1); ans
%=mod
; ans
+=mod
; ans
%=mod
;printf("Case %d: %lld\n",__
,ans
%mod
);}return 0;
}
                            總結
                            
                                以上是生活随笔為你收集整理的FZU - 2042 The Mad Mathematician 数位dp + 算贡献的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。