【bzoj 1833】【codevs 1359】 [ZJOI2010]count 数字计数(数位dp)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                【bzoj 1833】【codevs 1359】 [ZJOI2010]count 数字计数(数位dp)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                1833: [ZJOI2010]count 數字計數
Time Limit:?3 Sec??Memory Limit:?64 MBSubmit:?2774??Solved:?1230
[Submit][Status][Discuss]
Description
給定兩個正整數a和b,求在[a,b]中的所有整數中,每個數碼(digit)各出現了多少次。Input
輸入文件中僅包含一行兩個整數a、b,含義如上所述。Output
輸出文件中包含一行10個整數,分別表示0-9在[a,b]中出現了多少次。Sample Input
1 99Sample Output
9 20 20 20 20 20 20 20 20 20HINT
30%的數據中,a<=b<=10^6;
 100%的數據中,a<=b<=10^12。
Source
Day1
【題解】【數位dp】
[自己亂搞的結果就是寫了三遍。。。每一遍想法都有所改變……蠢哭]
【剛開始想的是用f[i][j][k][o][x][y]表示第i位放j時k的出現次數,o表示前導0,x,y表示是否到達左右邊界,每次下一位與當前位的相同時,更新時就加1,然后,怎么搞都錯成一團。。。扔掉!】
【然后,又考慮用f[i][j][k][o][x][y]表示第i位放j時j出現的次數k,o表示前導0,x,y表示是否到達左右邊界,每一次都是加上更新過來的f[i][j][k][o][x][y],然后,發現怎么搞1都不對。。。又扔掉!】
【最后,結合前兩次的經驗,先循環一重當前要求數t的出現次數,用f[i][j][k][o][x][y]表示第i位放j時t的出現次數k,o表示前導0,x,y表示是否到達左右邊界。循環9次,卡過了。。。】
【注意,這種方法,由于要判斷前導0,把零先去掉了,如果區間中包含0的話,要特判】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll a,b,ans;
int al[15],ar[15],left[15],right[15],l,r,len;
int f[15][12][15][3][3][3];
int main()
{freopen("int.txt","r",stdin);freopen("my.txt","w",stdout);int i,j,k,xx;scanf("%lld%lld",&a,&b); xx=a;while(a) left[++l]=a%10,a/=10;while(b) right[++r]=b%10,b/=10;len=max(l,r);memset(f,0,sizeof(f));for(i=1;i<=len;++i) al[len-i+1]=left[i],ar[len-i+1]=right[i];for(int t=0;t<=9;++t){memset(f,0,sizeof(f));for(i=al[1];i<=ar[1];++i) f[1][i][i==t&&i!=0][i==0][i==al[1]][i==ar[1]]=1;for(i=1;i<len;++i)for(j=0;j<=9;++j)for(k=0;k<=12;++k)for(int o=0;o<=1;++o)for(int x=0;x<=1;++x)for(int y=0;y<=1;++y)if(f[i][j][k][o][x][y]){if(x&&y){for(int h=al[i+1];h<=ar[i+1];++h){int p;if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];else p=0,f[i+1][h][0][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];}continue;	} 	if(!x&&!y){for(int h=0;h<=9;++h){int p;if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];else p=0,f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];}continue;	}if(!x){for(int h=0;h<=ar[i+1];++h){int p;if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];else p=0,f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];}continue;	}if(!y){for(int h=al[i+1];h<=9;++h){int p;if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];else p=0,f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];}continue;	}}ans=0;for(i=0;i<=9;++i)for(j=1;j<=12;++j)for(k=0;k<=1;++k)ans+=(ll)(f[len][i][j][k][1][1]+f[len][i][j][k][1][0]+f[len][i][j][k][0][1]+f[len][i][j][k][0][0])*j;if(!t&&!xx) printf("%lld ",ans+1);else printf("%lld ",ans);if(t==9) printf("\n");}return 0;
}轉載于:https://www.cnblogs.com/lris-searching/p/9403064.html
總結
以上是生活随笔為你收集整理的【bzoj 1833】【codevs 1359】 [ZJOI2010]count 数字计数(数位dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 混开头的成语有哪些?
- 下一篇: 06章 映射一对多双向关联关系、以及ca
