SPOJ - BALNUM Balanced Numbers(数位dp+进制转换)
題目鏈接:點擊查看
題目大意:給出平衡數的定義:每一個偶數出現的次數必須是奇數次,每一個奇數出現的次數必須是偶數次,求給定區間中有多少個平衡數
題目分析:數位dp,這個題目就難在怎么確定狀態轉移,本來我看錯題目了,以為只要有奇數個偶數和偶數個奇數就行,但還是想的太簡單了,看了網上大佬們的題解才知道,原來我們可以把每一個數字的狀態壓縮,每一個數字都有三種狀態:0表示沒出現過,1表示出現了奇數次,2表示出現了偶數次,普通的狀態壓縮都是0和1的兩種狀態,這個題有三種狀態,所以我們用三進制來儲存就好了,三的11次方沒超過60000,所以dp數組開dp[20][60000]就好,dp[i][j]代表在第i位,狀態位j時的符合條件的數量,在轉移狀態的時候我用到了一個change函數,具體怎么實現的非常巧妙,也算是學到了進制轉換的一點小技巧,假如想修改第i位上的數字時(從右向左的第i個),我們需要先得到第i位上的數字是多少,常規操作是先一直除3,直到讓第i位變成當前的個位,然后對3取模即可,如果想增加的話也是需要加三的i次方,聽起來好像已經很簡單了,但是卻有更簡單的方法,就是利用一個輔助數組f儲存3的i次方(1<=i<=10),然后用表示狀態的數對f[i+1]取余先令其范圍變為0~f[i+1],然后在繼續除以f[i],就可以直接獲得第i位上的數了,具體的看代碼吧:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<cmath> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=20; LL dp[N][60000];//dp[pos][sta]int b[N];int f[N];//儲存3的i次方bool check(int sta) {for(int i=0;i<=9;i++,sta/=3){if((i&1)&&sta%3==1)return false;if(!(i&1)&&sta%3==2)return false;}return true; }int change(int sta,int i) {int x=(sta%f[i+1])/f[i];//獲得第i位上的數if(x==2)return sta-f[i];elsereturn sta+f[i]; }LL dfs(int pos,int sta,bool lead,bool limit) {if(pos==-1)return check(sta);if(!limit&&dp[pos][sta]!=-1)return dp[pos][sta];LL ans=0;int up=limit?b[pos]:9;for(int i=0;i<=up;i++){if(lead&&i==0)ans+=dfs(pos-1,0,true,limit&&i==b[pos]);elseans+=dfs(pos-1,change(sta,i),false,limit&&i==b[pos]);}if(!limit)dp[pos][sta]=ans;return ans; }LL solve(LL n) {int cnt=0;while(n){b[cnt++]=n%10;n/=10;}return dfs(cnt-1,0,true,true); }int main() { // freopen("input.txt","r",stdin)int w;cin>>w;f[0]=1;for(int i=1;i<=10;i++)f[i]=f[i-1]*3; memset(dp,-1,sizeof(dp));while(w--){LL a,b;scanf("%lld%lld",&a,&b);printf("%lld\n",solve(b)-solve(a-1));}return 0; }?
總結
以上是生活随笔為你收集整理的SPOJ - BALNUM Balanced Numbers(数位dp+进制转换)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 4856 Tunnels(哈
- 下一篇: POJ - 4045 Power Sta