codeforces 401D D. Roman and Numbers(状态压缩dp+数论)

来源:互联网 发布:多宝视弱视训练软件 编辑:程序博客网 时间:2024/05/22 10:30

题目链接:

codeforces 401D


题目大意:

给出一个数字num,和一个数字mod,重新排列num的数位上的数字,问能够得到整除mod的方案数。


题目分析:

  • 首先我们定义S为一个数字的集合,dp[s][num]表示利用S里的数字构成%mod的余数为num的方案数。
  • 那么初始状态就是dp[0][0]==1
  • 转移就是枚举每个数位上的数字,得到新的状态s|(1<< j),然后当前枚举的数字作为最后一位数的方案数。注意当s为0的时候不能用0,因为0不能作为最高位,题目要求不能有前缀0
  • 因为有的数位会出现相同的数字,所以最后要除去每个数字内部出现全排列的情况

AC代码:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#define MAX (1<<18)using namespace std;typedef long long LL;LL dp[MAX][107];int n,m;LL fac[MAX];int num[MAX];char s[50];int main ( ){    while ( ~scanf ( "%s" , s ) )    {        scanf ( "%d" , &m );        n = strlen ( s );        int total = 1<<n;        memset ( num , 0 , sizeof ( num ) );        memset ( dp , 0 , sizeof ( dp ) );        dp[0][0] = 1;        fac[0] = 1;        for ( LL i = 0 ; i < n ; i++ )        {            fac[i+1] = fac[i]*(i+1LL);            num[s[i]-48]++;        }        for ( int i = 0 ; i < total ; i++ )            for ( int k = 0 ; k < m ; k++ )            {                if ( !dp[i][k] ) continue;                for ( int j = 0 ; j < n ; j++ )                {                    int x = s[j]-48;                    if ( x == 0 && i == 0 ) continue;                    if ( (1<<j)&i ) continue;                    int y = (1<<j)|i;                    int z = (k*10LL+x)%m;                    dp[y][z] += dp[i][k];                }            }        LL temp = 1;        for ( int i = 0 ; i < 10 ; i++ )            temp *= fac[num[i]];        printf ( "%lld\n" , dp[total-1][0]/temp );    }}
0 0
原创粉丝点击