数位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\n",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("\n");
else printf(" ");
}
//printf("\n");
return 0;
}
寻找真正的热爱

浙公网安备 33010602011771号