Codeforces Round #235 (Div. 2) D. Roman and Numbers 解题报告(状态压缩)

11 篇文章 0 订阅
D. Roman and Numbers
time limit per test
4 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Roman is a young mathematician, very famous in Uzhland. Unfortunately, Sereja doesn't think so. To make Sereja change his mind, Roman is ready to solve any mathematical problem. After some thought, Sereja asked Roma to find, how many numbers are close to number n, modulo m.

Number x is considered close to number n modulo m, if:

  • it can be obtained by rearranging the digits of number n,
  • it doesn't have any leading zeroes,
  • the remainder after dividing number x by m equals 0.

Roman is a good mathematician, but the number of such numbers is too huge for him. So he asks you to help him.

Input

The first line contains two integers: n (1 ≤ n < 1018) and m (1 ≤ m ≤ 100).

Output

In a single line print a single integer — the number of numbers close to number n modulo m.

Sample test(s)
input
104 2
output
3
input
223 4
output
1
input
7067678 8
output
47
Note

In the first sample the required numbers are: 104, 140, 410.

In the second sample the required number is 232.

    解题报告: 昨晚CF的题。昨晚三十几分钟搞定了前3题,简单看了一下,感觉没什么思路,就直接睡觉去了。早上看到队友说他写状态压缩,赛后过了。想了一下,的确可以过:dp[i][j],i的二进制表示数字有没有被使用,j表示余数,dp[i][j]表示使用i代表的那些数字后余数为j的数量。然后,状态压缩计算即可。代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
LL dp[500000][100];
char str[20];
int num[10];

int main()
{
    int n,m;
    scanf("%s%d",str,&m);
    int len = strlen(str);

    for(int i=0;i<len;i++) if(str[i]!='0')
        dp[1<<i][(str[i]-'0')%m]++;

    for(int i=2;i<(1<<len);i++)
    {
        for(int j=0;j<len;j++) if(i&(1<<j))
        {
            int old = i^(1<<j);
            for(int k=0;k<m;k++) if(dp[old][k])
            {
                dp[i][(k*10+str[j]-'0')%m]+=dp[old][k];
            }
        }
    }

    LL ans = dp[(1<<len)-1][0];

    for(int i=0;i<len;i++)
        num[str[i]-'0']++;

    for(int i=0;i<10;i++)
        for(int j=2;j<=num[i];j++)
            ans/=j;

    printf("%I64d\n", ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值