統計d(1~9)在數字0~n裏面出現的個數(數位dp)

規律:
首先枚舉個位,十位,百位…,然後對於每一位,作爲數字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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章