51nod:數字1的數量(線性dp or 數位dp)
阿新 • • 發佈:2019-01-31
Input
輸入N(1 <= N <= 10^9)Output
輸出包含1的個數Input示例
12Output示例
5
題目思路:
這道題資料這麼大顯然不能直接求得,想的時候一下子就想出來dp的方法(不過轉移狀態的時候,有個·地方是減一還是加一一直沒搞清楚,想了挺久才搞清楚),但是沒反映出來是dp,可能只是用到dp儲存之前節點的值的概念,不過,沒關係能想到dp的方法就好了,首先我們為什麼會想到用dp,因為對於一個數,高位的數字1的數量是乘以低位數字的數量,比如538,加入前兩位的數字1的數量是35,那麼高位的數字1的數量就5*35了,這個很容易想到吧,然後我們自然就知道是用dp了,這樣我們就很容易定義出狀態dp[i]為i位數1的數量那麼答案就是所有的dp[i]相加了,雖然狀態很容易定義出來,狀態轉移也不難想出來,但是有一點細節需要考慮,就是我們轉移狀態的時候分為等於1和大於1的情況,大於一的時候我們是轉移x*num[i-1]還是(x-1)num[i-1]呢一開始我以為是後者,wa的天昏地暗,腦子不夠清醒,忘記自己的狀態定義的是什麼了,我們狀態定義的是第i位數一的數量 比如321 dp[1]就是1~1的1的數量,dp【2】就是10~21的數量,dp【3】就是100~321的數量,那麼這樣的話我們就知道是x-1還是x了,顯然是x的,因為這裡dp【i-1】有一部分沒有算到,就是21~100的部分,然後對於第i為300~321的也不好算,但是剛好和前面那部分相加起來就是一個num【i-1】所以是x,另外還要注意當前位是1的情況
num【i】代表1~1^i的一的數量
ac程式碼:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<sstream> #include<map> #include<cmath> #define LL long long #define INF 0x3f3f3f3f using namespace std; int dp[20]; int num[20]; string s; int main() { while(cin>>s) { int len = s.size(); reverse(s.begin(),s.end()); memset(num,0,sizeof(num)); memset(dp,0,sizeof(dp)); int last = 1; for(int i = 0;i<len;i++ ) { if(i==0) { dp[i] = s[i]=='0'?0:1; num[i] = 1; } else { num[i] = num[i-1]*10+pow(10,i); if(s[i]>'1') { dp[i] = (s[i]-'0')*num[i-1]+pow(10,i); } else if(s[i] == '1') { int tmp = 0; for(int j = i-1 ;j>=0;j--) tmp = tmp*10+(s[j]-'0'); dp[i] = num[i-1]+1+tmp; } } } int ans = 0; for(int i = 0 ;i<len;i++) { // cout<<dp[i]<<endl; ans+=dp[i]; } cout<<ans<<endl; } }