题目链接:
http://codeforces.com/problemset/problem/258/B
 
题目意思:
给你一个m(m<=1^9),把1-m这m个数拿出7个分给7个政党,要求其中一个政党分配的数中含4和7的总个数比其他6个政党含4和7的总数还要多,求分配的总的种数,对1000000007求余。
解题思路:
先用数位dp,求出含有0个4或7的数的个数,含有1个4或7的数的个数,含。。。。。
dp[cur][last][sum]:表示还有cur位,前面一共含有last个4或者7,总共要求含有sum个4或者7的总的个数
然后分配的时候用递归来实现,其中组合数求余用到了求逆元的方法。
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF (1<<30)
#define PI acos(-1.0)
using namespace std;
#define mod 1000000007
#define ll __int64
int num[15];
int dp[15][15][15],pos[15];
int dfs1(int cur,int last,int sum,int flag)
{
   if(!cur)
   {
      if(last==sum)
         return 1;
      return 0;
   }
   if(last>sum)
      return 0;
   if(!flag&&dp[cur][last][sum]!=-1)
   {
      return dp[cur][last][sum];
   }
   int Max=flag?pos[cur]:9,numm=0;
   for(int i=0;i<=Max;i++)
   {
      if(i==7||i==4)
         numm+=dfs1(cur-1,last+1,sum,flag&&i==Max);
      else
         numm+=dfs1(cur-1,last,sum,flag&&i==Max);
   }
   if(!flag)
      dp[cur][last][sum]=numm;
   return numm;
}
void Cal(int m)
{
   int tt=0;
   while(m)
   {
      ++tt;
      pos[tt]=m%10;
      m/=10;
   }
   for(int i=0;i<=9;i++) //表示含有i个4或者7的总数
      num[i]=dfs1(tt,0,i,1);
}
ll AA(int n,int m)
{
   ll res=1;
   for(int i=n;i>=n-m+1;i--)
      res=(res*i)%mod;
   return res;
}
ll quick(ll m,ll n)  //快速幂求m^n%mod
{
   ll res=1;
   while(n)
   {
      if(n&1)
         res=(res*m)%mod;
      m=(m*m)%mod;
      n=n>>1;
   }
   return res;
}
ll CC(int n,int m)  //求组合数C(n,m)
{
   ll res=AA(n,m);
   ll temp=1;
   for(int i=2;i<=m;i++)
      temp=(temp*i)%mod;
   return (res*quick(temp,mod-2))%mod;
}
ll dfs2(int start,int sum,int left) //搜索求总的排列数
{
   if(left==0) //选出了6个政党
      return AA(6,6); //A66 采用先选后排的方法
   if(start<0) //不够
      return 0;
   ll res=0;
   for(int i=0;i<=num[start]&&(start*i)<sum&&i<=left;i++)
      res=(res+(CC(num[start],i)*dfs2(start-1,sum-start*i,left-i))%mod)%mod;
   return res;
}
int main()
{
   int m;
   memset(dp,-1,sizeof(dp));
   while(scanf("%d",&m)!=EOF)
   {
      memset(num,0,sizeof(num));
      Cal(m);
      num[0]--; //题目要求从1-m
      ll ans=0;
      for(int i=9;i>=1;i--)
         if(num[i])
            ans=(ans+(num[i]*dfs2(i-1,i,6))%mod)%mod;
      printf("%I64d\n",ans);
   }
   return 0;
}
 
 
                   
                   
                   
                   
                             本文介绍了解决CodeForces 258B问题的一种方法,通过数位DP求出含特定数字的数的数量,并结合组合数学计算分配方案数。使用递归实现分配过程,通过求逆元方法处理组合数求模。
本文介绍了解决CodeForces 258B问题的一种方法,通过数位DP求出含特定数字的数的数量,并结合组合数学计算分配方案数。使用递归实现分配过程,通过求逆元方法处理组合数求模。
           
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   437
					437
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            