【分析】以前数位DP只会用模版,一直没有仔细考虑过,最近又碰到一些决定仔细理解下,这题是自己想出来的,虽然题目很简单,还是蛮有成就感的。
预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为:
if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);
else dp[i][j] = dp[i-1][9]+dp[i][j-1];
然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1);
这样总复杂度log(n)*10
【AC CODE】15ms
#include <bits/stdc++.h> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 11; int dp[MAXN][10];//dp[i][j]从1~以j开头的i位数中有几个1 int bit[MAXN]; int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); #endif int tmp = 10; rep(i,1,10) dp[1][i] = 1; repe(i,2,9) { rep(j,1,10) { if(j == 1) dp[i][j] = dp[i-1][9]+tmp; else dp[i][j] = dp[i][j-1]; dp[i][j] += dp[i-1][9]; } tmp *= 10; } int n,cnt = 0; scanf("%d", &n); tmp = n; while(tmp) { bit[++cnt] = tmp%10; tmp /= 10; } int ans = 0,sum = 0; per(i,cnt,1) { if(bit[i] == 0) continue; if(bit[i] == 1) ans += dp[i-1][9]+1+n%((int)pow(10,i-1)); else ans += dp[i][bit[i]-1]; } printf("%d\n", ans); return 0; }