cf 401D. Roman and Numbers 数位dp,状压

来源:互联网 发布:dns 协议端口号为53 编辑:程序博客网 时间:2024/05/18 00:06

题意:给出两个数n,m,求x的个数,x需满足,x可由n的各位数字重新排列得到;x无前导零;x%m==0;

分析:比较简单的一道数位dp,由于n最多只有17位,可以状态压缩,dp[s][v]表示用掉集合s中的数,余数为v的个数,状态转移方程dp[s+k][(v*10+dig[k])%m]+=dp[s][v];

#include<iostream>#include<string>#include<cstring>#include<cstdio>#include<cmath>#include<iomanip>#include<map>#include<algorithm>#include<queue>#include<set>#define inf 10000000#define pi acos(-1.0)#define eps 1e-8#define seed 131using namespace std;typedef pair<int,int> pii;typedef unsigned long long ULL;typedef long long LL;const int maxn=100005;LL n;int m;LL dp[1<<18][100];int dig[18];int d[10];int main(){    scanf("%I64d%d",&n,&m);    int k=0;    memset(d,0,sizeof(d));    while(n)    {        dig[k]=n%10;        d[dig[k]]++;        n/=10;        k++;    }    LL ans=1;    for(int i=0;i<10;i++)    {        while(d[i]>1)        {            ans*=d[i];            d[i]--;        }    }    memset(dp,0,sizeof(dp));    dp[0][0]=1;    for(int i=0;i<(1<<k);i++)    {        for(int j=0;j<m;j++)        {            if(dp[i][j]==0)                continue;            for(int f=0;f<k;f++)            {                if(i==0&&dig[f]==0)                    continue;                if(!((1<<f)&i))                {                    dp[i|(1<<f)][(j*10+dig[f])%m]+=dp[i][j];                    //dp[i|(1<<f)][(j*10+dig[f])%m]%=m;                }            }        }    }    cout<<dp[(1<<k)-1][0]/ans;    return 0;}


0 0
原创粉丝点击