偷得题面
设f[i]代表第i位上不算前导零每个数出现多少次
比如54321
首先是5,,5在万位上,那么个十百千位每个数都会出现至少5*f[bit]次,然后万位上,5以下的数都会出现,然后以此类推
最后加完所有位之后,在处理4321这样的跑不满的零位就好了qwq
代码
DFS版
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#define int long long
using namespace std ;
int read() {
int x = 0 , f = 1 ; char s = getchar() ;
while(s > '9' || s < '0') {if(s == '-') f = -1 ; s = getchar() ;}
while(s <='9' && s >='0') {x = x * 10 + (s-'0'); s = getchar() ;}
return x*f ;
}
int l , r ;
int f[15][15] , num[15] ;
int dfs(int pos,int sum ,int lead ,int limit,int d) {
if(!pos) return sum ;
if(!limit&&f[pos][sum]!=-1&&!lead) return f[pos][sum] ;
int up = limit? num[pos] : 9 ;
int ans = 0 ;
for(int i = 0 ; i <= up ; i ++) {
ans += dfs(pos-1,sum+((i||!lead)&&(i==d)),lead&&(i==0) , limit && (i == num[pos]),d) ;
}
if(!lead && !limit) f[pos][sum] = ans ;
return ans ;
}
int calc(int x,int d) {
int len = 0 ;
while(x) {
num[++len] = x % 10 ;
x /= 10 ;
}
memset(f,-1,sizeof f) ;
return dfs(len,0,1,1,d) ;
}
signed main () {
l = read() , r = read() ;
for(int i = 0 ; i < 10 ; i ++) {
cout << calc(r,i) - calc(l-1,i) << " " ;
}
return 0 ;
}
循环
#include <bits/stdc++.h>
#define int long long
using namespace std ;
int a , b ;
int ten[15] , f[15] ;
int cnta[15] , cntb[15] , num[10] ;
void work(int x ,int cnt[]) {
for(int i = 0 ; i < 10 ; i ++) num[i] = 0 ;
int len = 0 ;
while(x) {//拆数
num[++len] = x%10 ;
x = x / 10 ;
}
for(int i = len ; i >= 1 ; i --) {
for(int j = 0 ; j <= 9 ; j ++) {
cnt[j] += f[i-1] * num[i] ; //第i位之后的每位每个数数都会出现i次
}
for(int j = 0 ; j < num[i] ; j ++) {
cnt[j] += ten[i-1] ;//第i位是x,那么在x之前的都会在出现10^(bit-1)次
}
//--------以上只是处理A000000....00这亚子----------//
//--------以下处理零位--------//
int num2 = 0 ;
for(int j = i-1 ; j >= 1 ; j --) {
num2 = num2 * 10 + num[j] ;//加上零位
}
cnt[num[i]] += num2 + 1 ;// num2是零位,1是最高位
cnt[0] -= ten[i-1] ;//清除前导零
}
}
signed main () {
scanf("%lld%lld",&a,&b) ;
ten[0] = 1 ;//10的阶乘,每一位代表多少
for(int i = 1 ; i <= 15 ; i ++) {
f[i] = f[i-1] * 10 + ten[i-1] ;//在第i位有数字的时候,每个数码有多少个
ten[i] = 10*ten[i-1] ;
}
work(a-1,cnta) ;//work(0-x的各数位,统计答案的数组)
work(b,cntb) ;
for(int i = 0 ; i <= 9 ; i ++) printf("%lld ",cntb[i] - cnta[i]) ;
return 0 ;
}
举个栗子: 32345
首先 是 5f[0] ,然后4f[1] (也就是4个一位数所有的数,因此当前位数4是没有算上的),然后是3*f[2] (也就是4个两位数所有的数,因此当前位数3是没有算上的)....以此类推
然后我们成功的处理完len-1位(y因为这些位数一定是合法的)后,开始考虑len位,首先,num[len]-1个ten[i-1]次(y因为最后一位不算零头也只能出现这些),然后在填上零头就好了