2020ICPC(上海) - Sum of Log(數位dp)
阿新 • • 發佈:2020-12-18
題目連結:點選檢視
題目大意:給出X 和 Y,求
題目分析:因為涉及到了位運算且看似可以遞推,所以考慮數位dp,因為統計答案時的 i 和 j 的與為 0,所以 i + j = i & j,那麼取 log 其實就是最高位,也就是 max( highbit_i , highbit_j )
最簡單的狀態就是:dp[ pos ][ highbit_x ][ highbit_y ][ x <= X ][ y <= Y ],不過很可惜會 TLE
因為我們到達終點後,我們只關心 max( highbit_x , highbit_y ),所以狀態優化為dp[ pos ][ max( highbit_x , highbit_y ) ][ x <= X ][ y <= Y ],很可惜還是會 TLE
然後就沒思路了,去看了題解恍然大悟,其實我們可以去列舉最高位的,假設 i 為最高位,也就是max( highbit_x , highbit_y ) 為 i,此時只有兩種情況:
- x 和 y 大於 i 的位置全為 0,x 的 i 為 1,y 的 i 為 0
- x 和 y 大於 i 的位置全為 0,x 的 i 為 0,y 的 i 為 1
每次都去數位 dp 即可,時間複雜度下降到了最終的 O( 2 * 35 * 2 * 2 ) ≈ O( 280 )
最後再補充一下,dp 陣列記憶化的實質上是當前狀態下有多少個 i & j ,最後的貢獻還是需要乘上相應的 highbit + 1
程式碼:
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std; typedef long long LL; typedef unsigned long long ull; const int inf=0x3f3f3f3f; const int N=1e3+100; const int mod=1e9+7; LL dp[35][2][2];//dp[pos][i<=x][j<=y] int A[35],B[35]; LL dfs(int pos,int f1,int f2) { if(pos==-1) return 1; if(dp[pos][f1][f2]!=-1) return dp[pos][f1][f2]; int upa=f1?A[pos]:1; int upb=f2?B[pos]:1; LL ans=0; for(int i=0;i<=upa;i++)//列舉A for(int j=0;j<=upb;j++)//列舉B if((i&j)==0) ans=(ans+dfs(pos-1,f1&&i==upa,f2&&j==upb))%mod; return dp[pos][f1][f2]=ans; } LL solve(int x,int y) { memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(dp,-1,sizeof(dp)); int cnt1=0,cnt2=0;//highbit int xx=x,yy=y; while(xx) { A[cnt1++]=xx&1; xx>>=1; } while(yy) { B[cnt2++]=yy&1; yy>>=1; } LL ans=0; for(int i=0;i<max(cnt1,cnt2);i++) { LL res=0; if(i<cnt1)//第i位x為1,y為0 res+=dfs(i-1,i==cnt1-1,i>=cnt2); if(i<cnt2)//第i為y為1,x為0 res+=dfs(i-1,i>=cnt1,i==cnt2-1); ans=(ans+res*(i+1))%mod; } return ans; } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false); int w; cin>>w; while(w--) { int x,y; scanf("%d%d",&x,&y); printf("%lld\n",solve(x,y)); } return 0; }