1. 程式人生 > >找出區間[A, B]內所有數字的奇數字位出現次數為偶數,偶數字位出現次數為計數的數的個數。(數位DP)

找出區間[A, B]內所有數字的奇數字位出現次數為偶數,偶數字位出現次數為計數的數的個數。(數位DP)

題目:找出區間[A, B]內所有數字的奇數字位出現次數為偶數,偶數字位出現次數為計數的數的個數。

 

分析:這道題的狀態同樣不好取,因為要求每一個奇數的個數都要為偶數,每一個偶數的位數都要為奇數,又因為只有10個數(0~9),又因為沒個數只有3種狀態,分別是沒有(0),奇數個(1),偶數個(2),這樣我們就利用3進位制進行壓縮就可以了,3的10次方不超過60000,因此直接開60000即可,這樣dp[i][j]的i表示當前處理到了第i為,j表示當前(0~9)對應的狀態

#include <cmath>
#include <cstdio>
#include <cstring>
#include 
<iostream> #include <algorithm> using namespace std; const int maxn = 25; typedef long long LL; LL dp[maxn][60000],bit[maxn]; int judge(int state){ //計算是否滿足題意,奇數為偶,偶數為奇 for(int i = 0; i <= 9; ++i, state/=3) { if((i&1)==1&&state%3==1) { return 0; }
if((i&1)==0&&state%3==2) { return 0; } } return 1; } int change(int state,int i){ int temp = state; int j = i; while(j--){///取到當前位 temp /= 3; } int x = temp%3; if(x == 0) state += (int)pow(3.0, i); else if(x == 1) state
+= (int)pow(3.0, i); else state -= (int)pow(3.0, i); return state; } LL dfs(int pos,int state,int limit){ if(pos < 1) return judge(state); LL &ans = dp[pos][state]; if(!limit && ans != -1) return ans; LL ret = 0; int len = limit?bit[pos]:9; for(int i = 0; i <= len; i++) ret += dfs(pos-1, state==0&&i==0?0:change(state, i), limit&&i==len); if(!limit) ans = ret; return ret; } LL solve(LL n){ int len = 0; while(n){ bit[++len] = n%10; n /= 10; } return dfs(len, 0, 1); } int main() { int T; scanf("%d", &T); LL A,B; memset(dp, -1, sizeof(dp)); while(T--){ scanf("%lld%lld", &A, &B); printf("%lld\n", solve(B)-solve(A-1)); } return 0; }
View Code