Problem Specification Value
Time Limit 10 Sec
Memory Limit 128 MB
Submit 1585
Solved 1004

Description

给一个数字串 s 和正整数 d, 统计 s 有多少种不同的排列能被 d 整除 (可以有前导 0). 例如 123434 有 90 种排列能被 2 整除, 其中末位为 2 的有 30 种, 末位为 4 的有 60 种.

Input

输入第一行是一个整数 T, 表示测试数据的个数, 以下每行一组 s 和 d, 中间用空格隔开. s 保证只包含数字 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.

Output

每个数据仅一行, 表示能被 d 整除的排列的个数.

Sample Input

7
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29

Sample Output

1
3
3628800
90
3
6
1398

HINT

在前三个例子中, 排列分别有 1, 3, 3628800 种, 它们都是 1 的倍数.

【限制】

100% 的数据满足: s 的长度不超过 10, 1<=d<=1000, 1<=T<=15

Source


按照每一位的数值来考虑接下来位数整除 d 的值, 也就是数位 DP.



#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn = 1010, maxm = 1025;

int cases, n, d, dp[maxm][maxn];
char str[30];

#define states(x) (1<<(x))

// dp[i][j] = modulo j @ state i.
void dp_work(void)
{
    // Similar to a memset().
    for (int i = 0; i < states(n); i++)
        for (int j = 0; j < d; j++)
            dp[i][j] = 0;
    // Putting nothing here has 1 choice.
    dp[0][0] = 1;
    // Iterate through all states by i.
    for (int i = 0; i < states(n); i++)
        // Iterate through all possible modulus by j.
        for (int j = 0; j < d; j++)
            // That is, at this state i we have some occurences. Now dispatch
            // the data to children.
            if (dp[i][j] > 0)
                // Now we iterate through all digits with x.
                for (int x = 1; x <= n; x++)
                    // If the current digit was not selected, then...
                    if (((1 << (x - 1)) & i) == 0)
                        // printf("dp @ %d %d %d -> %d\n", i, j, x, i & (1 << (x - 1)));
                        // The updated state.
                        dp[i | (1 << (x - 1))]
                        // The new modulo, we multiply 10 because a base-10
                        // digit was shifted forward.
                        [(str[x] + j * 10) % d]
                        // Update with addition of the current state.
                        += dp[i][j];
    return ;
}

int main(int argc, char** argv)
{
    scanf("%d", &cases);
    for (int idx = 1; idx <= cases; idx++) {
        scanf("%s%d", str + 1, &d);
        n = strlen(str + 1);
        int tot[10], perm[10];
        for (int i = 0; i < 10; i++) {
            tot[i] = 0;
            perm[i] = 1;
        }
        for (int i = 1; i <= n; i++) {
            // Convert into real numbers
            str[i] -= '0';
            // Deduct permutation duplication ( / P_n^n i.e. n! )
            tot[str[i]]++;
            perm[str[i]] *= tot[str[i]];
        }
        // Dynamically programming.
        dp_work();
        for (int i = 0; i < 10; i++)
            dp[(1 << n) - 1][0] /= perm[i];
        // Get result
        int res = dp[(1 << n) - 1][0];
        printf("%d\n", res);
    }
    return 0;
}

from pydatagen import *
T = randrange(10, 15)
printf('%d\n', T)
for i in range(0, T):
    d = randrange(100, 1000)
    n = randrange(1, 10)
    s = ''
    for j in range(0, n):
        s += str(randrange(0, 10))
    printf('%s %d\n', s, d)