给一个数m,在1到m当中先挑一个数出来,再从剩下的数当中挑6个数,要求这六个数保函数字4或7的个数严格小于挑出第一个数包涵的4或7..先递推求出dp[i][j],表示长度为i的数中,包涵j个4,7的数的个数,再从高位开始推,求出1-m当中,包涵k个4,7的分别有多少个(s[k])。思路挺好想,之前只做过一两道数位DP的题,结果递推式推出来各种呵呵....这东西果然是写多了就熟练了...
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
typedef long long ll;
int n,m,p,q;
ll num;
ll dp[20][20];
int bit[20];
ll s[20];
const ll mod=1000000007LL;
int sum;
int b[20];
ll dfs(int n,int m)
{
ll ret=0;
for (int i=0; i<=n; i++)
{
if (i>n) break;
if (m==1) ret+=s[i];
else
{
s[i]--;
ret+=(s[i]+1)*dfs(n-i,m-1);
s[i]++;
}
ret%=mod;
}
return ret;
}
int main()
{
// freopen("in.txt","r",stdin);
memset(dp,0,sizeof dp);
dp[0][0]=1;
for (int i=1; i<=10; i++)
for (int j=0; j<=9; j++)
for (int k=0; k<=i; k++)
if (j==4 || j==7)
{
if (k) dp[i][k]+=dp[i-1][k-1];
}
else dp[i][k]+=dp[i-1][k];
cin>>num;
num++;
// dp[1][0]--;
int len=0;
memset(bit,0,sizeof bit);
memset(s,0,sizeof s);
while(num) bit[++len]=num%10,num/=10;
int t=0;
for (int i=len; i>=1; i--)
{
for (int j=0; j<bit[i]; j++)
for (int k=t; k<=len; k++)
if (j==4 || j==7)
{
if (k-t)
s[k]+=dp[i-1][k-t-1];
}
else s[k]+=dp[i-1][k-t];
if (bit[i]==4 || bit[i]==7) t++;
}
s[0]--;
ll ans=0;
memset(b,0,sizeof b);
for (int i=1; i<=len; i++)
if (s[i]) sum=0,ans+=s[i]*dfs(i-1,6),ans%=mod;
cout<<ans<<endl;
// for (int i=0; i<=10; i++) cout<<s[i]<<endl;
return 0;
}