数位DP模板

https://www.luogu.com.cn/problem/P2602

挺简单 的其实,板子题

真实的模板

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int len,a[2000];
ll l,r,dp[20][15][25][25][20];

ll dfs(int pos,int pre,ll st,ll sum,int d,int lead,int limit)
//pos搜到的位置
//pre前一位数
//st当前公差最大差值
//sum整个数字的最大价值
//d共差
//lead判断是否有前导0
//limit判断是否有最高位限制

{
    if(pos>len) return sum;//dp结束 
    //记录状态(计划搜索)
    //注意d有负数,最小可以到-9,所以记录时数组下标是d+10 
    if((dp[pos][pre][st][sum][d+10]!=-1&&(!limit)&&(!lead))) return dp[pos][pre][st][sum][d+10]; 
    ll ret=0;
    int res=limit?a[len-pos+1]:9;//最高位最大值 
    for(int i=0;i<=res;i++)
    {
        //有前导0且这位也是前导0,一切不变只有位数变化 
        if((!i)&&lead) ret+=dfs(pos+1,0,0,0,-38,1,limit&&(i==res));
        //有前导0但这位不是前导0(这位是数字的最高位)开始有前一位,一个数形成等差数列 
        else if(i&&lead) ret+=dfs(pos+1,i,1,1,-38,0,limit&&(i==res));
        //之前刚搜到1位还没有共差,两位数形成等差数列,记录共差 
        else if(d<-9) ret+=dfs(pos+1,i,2ll,2ll,i-pre,0,limit&&(i==res));
        //搜到2位以后,共差若与前两位相同当前等差数列长度增加,若公差变化则更新整个数字的最大价值,等差数列长度又变为2 
        else if(d>=-9) ret+=dfs(pos+1,i,(i-pre==d)?st+1:2,max(sum,(i-pre==d)?st+1:2),(i-pre==d)?d:i-pre,0,limit&&(i==res));
    }
    //没有前导0和最高限制时可以直接记录当前dp值以便下次搜到同样的情况可以直接使用。 
    return (!limit&&!lead)?dp[pos][pre][st][sum][d+10]=ret:ret;
}



ll part(ll x)
{
    len=0;
    while(x) a[++len]=x%10,x/=10;
    memset(dp,-1,sizeof dp);
    return dfs(1,0,0,0,-38,1,1);//-38是随便赋的其实赋成-10就行了…… 
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&l,&r);
        //l是0的时候要特别注意!
        printf("%lld
",l?(part(r)-part(l-1)):(part(r)-part(l)+1));
    }
    return 0;
}

  

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 100+11;
ll dp[maxn][maxn];//第i位置的x有dp[i][][x]个
ll list[maxn];

ll dfs(int cur,int up,int lead,int val,ll sum) { //cur位置,用了sum个数字 ,lead ==1有前导0
	if(cur == 0) return sum;
	if(!up&&lead&&dp[cur][sum] != -1) return dp[cur][sum];
	int lim = 9;
	if(up) lim = list[cur];
	ll cns =0 ;

	for(int i=0; i<=lim; i++) {
		cns += dfs(cur-1,up && (i == lim),i || lead,val,sum + ((i == val) && (i || lead)));
	}

	if(!up && lead) dp[cur][sum] = cns;
	return cns;
}


vector<ll>ins;

int cal(ll n) {



	ll cnt =0;

	while(n) {
		list[++cnt] = n%10;
		n /= 10;
	}
	for(int i=0; i<10; i++) {
		memset(dp,-1,sizeof(dp));
		ins.push_back(dfs(cnt,1,0,i,0));
	}


}

int main() {

	ll l,r;
	scanf("%lld %lld",&l,&r);
	cal(r);
	cal(l-1);

	for(int i=0; i<ins.size()-10; i++) {
		printf("%lld",ins[i] - ins[i+10]);
		if(ins.size() - 9 == i) printf("
");
		else printf(" ");
	}
	//printf("
");

	return 0;
}





寻找真正的热爱
原文地址:https://www.cnblogs.com/lesning/p/13641994.html