codeforces 258B - Little Elephant and Elections 数位DP

         给一个数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;
}


你可能感兴趣的:(codeforces 258B - Little Elephant and Elections 数位DP)