规律:
首先枚举个位,十位,百位…,然后对于每一位,作为数字d的时候,包含的数字有多少个,分为这个数的左右2端。
比如12345,要求d=4有多少个,对于十位,这一位取4,分成12300和45来看,对于12300,十位取4,其左边是有123种情况,右边有10种,所以总数就是1230,然后对于45,取4的情况有6种。然后对于百位也同样道理。
code(以7为例)
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair<int,int>
#define pal pair<ll,ll>
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
char str[man];
int fac[man],s[man];
signed main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t;
scanf("%d",&t);
fac[0] = 1;
For(i,1,man-1)fac[i] = 1ll * fac[i-1] * 10 % mod;//处理10^i
while(t--){
scanf("%s",str+1);
int n = strlen(str+1);
For(i,1,n)s[i] = (10ll * s[i-1] + (str[i]-'0'))%mod;//计算前缀对mod取模
ll ans = 0,tp = 0;
Rep(i,n,1){
ans = (ans + 1ll * s[i-1] * fac[n-i]% mod )%mod;//计算左右总的个数
if(str[i]=='7')ans = (ans + tp + 1)%mod;//对于后一部分的计算
else if(str[i]>'7')ans = (ans + fac[n-i])%mod;
tp = (tp + 1ll*(str[i]-'0')*fac[n-i])%mod;
}
printf("%d\n",ans);
}
return 0;
}
数位dp
维护为d(0~9)的个数和总的个数,当为7的时候,直接把之前总的个数加到d的个数上。记忆化一下
以7位例
落谷P2602
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair<int,int>
#define pal pair<ll,ll>
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
int str[man];
int n;
pal dp[man];
template<typename t1,typename t2>
const pair<t1,t2> operator + (const pair<t1,t2> &a,const pair<t1,t2> &b){
return {a.first + b.first,a.second +b.second};
}
int d;
pal dfs(int pos,bool limit,bool lead){
if(pos==0)return {0,1};
pal &x = dp[pos];
if(!limit&&!lead&&x.first!=-1)return x;
int up = limit ? str[pos] : 9;
pal ans = {0,0};
for(int i = 0;i <= up;++i){
pal tp = dfs(pos-1,limit&&i==up,lead&&i==0);
ans = ans + tp;
if(lead&&i==0)continue;//判断前导0,如果有前导0并且当前为0,不统计当前位的答案。
//如果有前导0,但i不等于0,该答案还是要统计,无前导0,i等于0,依旧统计答案。
if(i==d)ans.first += tp.second;
}
if(!limit&&x.first==-1&&!lead)x = ans;
return ans;
}
ll slove(ll x){
int pos = 0;
while(x){
str[++pos] = x % 10;
x /= 10;
}
return dfs(pos,1,1).first;
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t;
for(int i = 0;i < man;++i)dp[i] = {-1,0};
ll a,b;
cin >> a >> b;
for(int i = 0;i <= 9;++i){
d = i;
printf("%lld ",slove(b)-slove(a-1));
}printf("\n");
return 0;
}