题目:给出不多1000位的数,每一位由0、1、2、3组成。
条件:所有的0都在1之前,所有的2都在3之前,0不能在首位,另外0、1、2、3必须出现至少一次。由于数较大所以结果对1000000007取余。
问题:求满足条件的数的数量。
条件:所有的0都在1之前,所有的2都在3之前,0不能在首位,另外0、1、2、3必须出现至少一次。由于数较大所以结果对1000000007取余。
问题:求满足条件的数的数量。
分析:明显这类题目是无法通过暴力遍历解决的。所以需要通过数位dp解决。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[1005][2][2][2][2],digit[1005];
void init()
{
memset(dp,-1,sizeof(dp)); //初始化dp数组
}
int dfs(int len,int i,int j,int k,int l,int flag) //len表示当前位,i,j,k,l分别表示是否包含0、1、2、3(0表示不包含,1表示包含),flag表示是否达到上限(1为达到,0为未达到)
{
if(len<=0)
return (i&&j&&k&&l);
if(!flag&&dp[len][i][j][k][l]!=-1)
return dp[len][i][j][k][l];
int n=flag?digit[len]:3;
int ans=0;
for(int i1=0;i1<=n;i1++)
{
int i2=i,j1=j,k1=k,l1=l;
if(j==0&&k==0&&l==0&&i1==0)
continue;
if(i1==0&&j==1)
continue;
else if(i1==0&&j==0)
i2=1;
else if(i1==1&&i==0)
continue;
else if(i==1&&i1==1)
j1=1;
else if(i1==2&&l==1)
continue;
else if(i1==2&&l==0)
k1=1;
else if(i1==3&&k==0)
continue;
else if(i1==3&&k==1)
l1=1;
ans=(ans+dfs(len-1,i2,j1,k1,l1,flag&&i1==n))%1000000007;
}
if(!flag)
dp[len][i][j][k][l]=ans;
return ans;
}
int main()
{
int n,summ;
scanf("%d",&n);
init();
digit[n]=2;
for(int i=n-1;i>0;i--)
digit[i]=3;
summ=dfs(n,0,0,0,0,1);
printf("%d\n",summ);
return 0;
}
另外,数位dp上面这种实现方式必须dfs函数的for循环对于i,j,k,l形参的操作必须重新定义变量,而不能直接使用原变量,因为这可能导致for循环的下一个循环的变量i,j,k,l改变。