动态规划六
复健\(Day4\)
动态规划(六)数位\(DP\)
数位\(DP\)的特点:求某个区间\([l,r]\)内,满足某种性质的数的个数
技巧一:类似前缀和的思想,转化为\([0,r]-[0,l-1]\)求解
技巧二:从高位到低类填数,分类讨论;
比如比\(R\)小的数的个数,对于数\(R=a_{n}a_{n-1}\cdots a_n\),如果某一位填了\(0-a_i\),则后面每一位都可填\(0-9\)的任意数,如果填\(a_i\),则继续讨论下一位(这样才不会大于\(R\))
\(1.\)数字游戏
\(f[i][j]\)表示一共有\(i\)位,且最高位数字为\(j\)的不降数个数
\(f[i][j]=\sum_{k=j} ^{9} f[i-1][k]\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 12
using namespace std;
int a[maxn],f[maxn][maxn];
void init()
{
for(int i=0;i<=9;i++) f[1][i]=1;
for(int i=2;i<=maxn;i++)
{
for(int j=0;j<=9;j++)
{
for(int k=j;k<=9;k++) f[i][j]+=f[i-1][k];
}
}
}
int dp(int n)
{
if(!n) return 1;//特判,0也是一个不降数
int cnt=0;
while(n) a[++cnt]=n%10,n/=10;
int res=0,last=0;
for(int i=cnt;i>=1;--i)
{
int now=a[i];
for(int j=last;j<now;j++) res+=f[i][j];
if(now<last) break;
last=now;
if(i==1) res++;//就是0也是一个不降数
}
return res;
}
int main()
{
init();
int l,r;
while(cin>>l>>r)
{
cout<<dp(r)-dp(l-1)<<endl;
}
return 0;
}
\(2.\)\(windy\)数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define maxn 10
using namespace std;
int f[maxn][maxn];
void init()
{
for(int i=0;i<=9;i++) f[1][i]=1;
for(int i=2;i<=10;i++)
{
for(int j=0;j<=9;j++)
{
for(int k=0;k<=9;k++)
{
if(abs(k-j)>=2) f[i][j]+=f[i-1][k];
}
}
}
}
int dp(int n)
{
if(!n) return 0;
vector<int> a;
while(n) a.push_back(n%10),n/=10;
int last=-2;
int res=0;
for(int i=a.size()-1;i>=0;i--)
{
for(int j=(i==a.size()-1);j<a[i];j++)
{
if(abs(j-last)>=2) res+=f[i+1][j];
}
if(abs(a[i]-last)<2) break;
last=a[i];
if(!i) res++;
}
for(int i=a.size()-1;i>=1;i--)
{
for(int j=1;j<=9;j++) res+=f[i][j];
}
return res;
}
int main()
{
int a,b;
cin>>a>>b;
init();
printf("%d\n",dp(max(a,b))-dp(min(a,b)-1));
return 0;
}
\(3.\)度的数量
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 12
using namespace std;
int a[maxn],f[maxn][maxn];
int k,B;
void init()//预处理组合数
{
for(int i=0;i<=maxn;i++) f[i][0]=1;
for(int i=1;i<=maxn;i++)
{
for(int j=1;j<=i;j++)
{
f[i][j]=f[i-1][j-1]+f[i-1][j];
}
}
}
int dp(int n)
{
if(!n) return 0;//特判,0也是一个不降数
int cnt=0;
while(n) a[++cnt]=n%B,n/=B;
int res=0,last=0;
for(int i=cnt;i>=1;--i)
{
int now=a[i];
if(now)
{
res+=f[i-1][k-last];
if(now>1)
{
if(k-last-1>=0) res+=f[i-1][k-last-1];
break;
}
else
{
last++;
if(last>k) break;
}
}
if(i==1&&last==k) res++;
}
return res;
}
int main()
{
init();
int l,r;
cin>>l>>r>>k>>B;
cout<<dp(r)-dp(l-1)<<endl;
return 0;
}
正因无所有,才会无所畏