Description
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
Input
输入文件中仅包含一行两个整数a、b,含义如上所述。
Output
输出文件中包含一行10个整数,分别表示0−9在[a,b]中出现了多少次。
Sample Input
199
Sample Output
9202020202020202020
HINT
30%的数据中, a<=b<=106;
100%的数据中, a<=b<=1012。
Solution :
记 dp[i][less]表示做到第i位,是否贴着上限时0 9的个数以及此时一共有多少个数 ,我们先暴力枚举第一个非零位,然后dfs。
Code :
/************************************************************************* > File Name: bzoj1833.cpp > Author: Archer ************************************************************************/
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
const int N = 22;
typedef long long ll;
#define MS(_) memset(_, 0xff, sizeof(_))
struct info{
ll ans[N], cnt;
info() {memset(ans, 0, sizeof(ans)); cnt = 0;}
}dp[N][2];
char str[N];
int vis[N][2];
ll L, R;
info operator +(const info &x, const info &y){
info z; for (int i = 0; i <= N; i++) z.ans[i] = x.ans[i] + y.ans[i]; return z;
}
inline info dfs(int dep, int less){
info ret, pack;
if (~vis[dep][less]) { vis[dep][less] = 1; return dp[dep][less]; }
vis[dep][less] = 1;
if (dep >= strlen(str)){ ret.cnt = 1; dp[dep][less] = ret; return ret; }
for (int i = 0; i <= 9; i++)
if (less || i <= str[dep] - '0'){
pack = dfs(dep + 1, (less || i < str[dep] - '0') ? 1 : 0);
ret = ret + pack; ret.ans[i] += pack.cnt;
}
return dp[dep][less] = ret;
}
int main(){
scanf("%lld%lld", &L, &R); L--; MS(vis);
sprintf(str, "%lld", L); info Lans, pack;
for (int i = 0; i < strlen(str); i++)
for (int j = 1; j <= (i == 0 ? str[0]-'0' : 9); j++){
info pack = dfs(i + 1, (i == 0 && j == str[0] - '0') ? 0 : 1);
Lans = Lans + pack; Lans.ans[j] += pack.cnt;
}
sprintf(str, "%lld", R); info Rans; MS(vis);
for (int i = 0; i < strlen(str); i++)
for (int j = 1; j <= (i == 0 ? str[0]-'0' : 9); j++){
info pack = dfs(i + 1, (i == 0 && j == str[0] - '0') ? 0 : 1);
Rans = Rans + pack; Rans.ans[j] += pack.cnt;
}
for (int i = 0; i < 9; i++) printf("%lld ", Rans.ans[i] - Lans.ans[i]);
printf("%lld\n", Rans.ans[9] - Lans.ans[9]);
return 0;
}