Codeforces Round #157 (Div. 1)B 数位dp

//枚举有几个(7或4),用数位dp的记忆化搜索找有i个(7或4)的数又多少个
//暴力搜索在第i个中选几个
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int mod = 1e9 + 7;
int dp[20][20];//第i位有 j个数(7或者4)
int bit[20] ;
int temp[20];
int luck[20];
int dfs(int pos , int flag ,int max_flag, int lim)
{
    if(pos == 0)
    return flag == max_flag;
    if(!lim && dp[pos][flag] != -1)
    return dp[pos][flag] ;
    int num = lim ? bit[pos] : 9;
    int ans = 0 ;
    for(int i = 0;i <= num ;i++)
    {
        int flag_x = flag ;
        if(i == 7 || i == 4)
        flag_x++;
        ans += dfs(pos - 1 ,flag_x ,max_flag, lim && (i==num)) ;
    }
    if(!lim)dp[pos][flag] = ans ;
    return ans ;
}
//__int64 ans_ans = 0;
__int64 dfs_s(int res , __int64 ans ,int pos, int num ,int max_flag)
{
    if(num >= max_flag)
    return 0;
    if(res == 0)
        return  (ans * (__int64)temp[num+1])%mod;
    __int64 sum = 0;
    for(int i = 0 ;i <= pos;i++)
    {
        if(luck[i] > 0)
        {
            __int64 ans_x = ((ans*(__int64)luck[i])%mod);
            luck[i] -= 1;
            sum += dfs_s(res - 1 , ans_x , pos , num+i , max_flag) ;
            luck[i] += 1;
        }
    }
    return sum%mod;
}
__int64 solve(int n)
{
    if(n == 7)return 0;
    int t = n;
    int pos = 0;
    while(t)
    {
        bit[++pos] = t%10 ;
        t/=10 ;
    }
   memset(luck , 0 ,sizeof(luck)) ;
   memset(temp , 0 , sizeof(temp));
   for(int i = pos;i >= 0 ;i--)
   {
       memset(dp , -1 , sizeof(dp)) ;
       luck[i] = dfs(pos , 0 , i , 1) ;
       temp[i] = temp[i+1] + luck[i];
   }
   luck[0] -= 1;
  return dfs_s(6 , 1 , pos , 0 , luck[pos] ? pos : pos - 1) ;
}
int main()
{
   // freopen("input.txt" ,"r" ,stdin) ;
    int n ;
    while(~scanf("%d" ,&n))
    {
        printf("%I64d\n" ,solve(n)%mod) ;
    }
    return 0;
}















































你可能感兴趣的:(Codeforces Round #157 (Div. 1)B 数位dp)