码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces 401D Roman and Numbers

时间:2015-08-21 18:43:47      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:

题目简述:

给定n和m,求把n的各位数字重排后有多少数能被m整除(禁止有前导0的数)

n (1 ≤ n < 1018) and m (1 ≤ m ≤ 100).

本来是打算做一道数位DP的 然后看到了这题 也往数位DP上想 结果……

------------------------------------------------------------------------------------------------------

还是来说正解吧 正解是状压DP

我们可以用f[i][j]表示已用的数字集合为i,对m求余为j的方案数

每次往一个较小的集合所构成的数末尾添加一个数字得到一个较大的集合(这样前导0更方便处理)

然后注意不同位上的相同数字是等价的 于是最后还要除一下所有数字出现次数的阶乘

#include <bits/stdc++.h>
using namespace std;
long long f[1<<18][100];
int num[18],pos[1<<18],cnt[10];
long long n;
int m,top;
int main()
{
    scanf("%lld%d",&n,&m);
    int tmp=1;
    while(n)
    {
        cnt[n%10]++;
        pos[tmp]=n%10;
        num[top++]=n%10;
        n/=10;
        tmp<<=1;
    }
    for(int i=1;i<(1<<top);++i)
        if(i==(i&-i))
            f[i][pos[i]%m]=(pos[i]!=0);
        else
        {
            for(int j=0;j<top;++j)
                if(i&(1<<j))
                    for(int k=0;k<m;++k)
                        f[i][(k*10+num[j])%m]+=f[i^(1<<j)][k];
        }
    long long ans=f[(1<<top)-1][0];
    for(int i=0;i<=9;++i)
        for(int j=1;j<=cnt[i];++j)
            ans/=j;
    printf("%lld",ans);
    return 0;
}

 

codeforces 401D Roman and Numbers

标签:

原文地址:http://www.cnblogs.com/sagitta/p/4748542.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!