题目大意:
将一个x的数位重组能够等于n,并且x%m=0,没有前导零,问有多少个这样的x?
解题思路:
mmp,一开始以为状压不可以,结果2^18=262144,意外(看题解)的发现可以,又因为m<=100,则可以设dp[262144 + 10][111]
则dp[p][Mod],(p拆分成二进制,选1的个数以及位置)的状态,对m取模=Mod 时满足条件的总个数
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool vis[20];
int cnt;
ll sum[20];
ll dp[(1 << 18) + 10][111], num[20];
ll n, m;
ll read() {
ll X = 0, p = 1; char c = getchar();
for (; c > '9' || c < '0'; c = getchar()) if (c == '-') p = -1;
for (; c <= '9' && c >= '0'; c = getchar()) X = X * 10 + c - '0';
return X * p;
}
/*ll dfs(int pos, int p, ll Mod) { //会超时,因为总状态数乘转移为5e8 ???可直接转移也为4e8
if (!pos) return (Mod % m == 0);
if (dp[p][Mod % m] != -1) return dp[p][Mod % m];
ll ans = 0;
for (int i = 1; i <= cnt; i++) {
if (vis[i] || pos == cnt && num[i] == 0) continue;
vis[i] = true;
ans += dfs(pos - 1, p + (1 << (i - 1)), (Mod * 10 + num[i]) % m);
vis[i] = false;
}
dp[p][Mod % m] = ans;
return ans;
}*/
ll solve(ll x) {
while (x) num[cnt++] = x % 10, x /= 10;
for (int i = 0; i < cnt; i++) sum[num[i]]++;
for (int i = 0; i < cnt; i++) if (num[i]) dp[1 << i][num[i] % m] = 1;//初始化状态
for (int i = 1; i < (1 << cnt) - 1; i++)
for (int k = 0; k < m; k++)
for (int j = 0; j < cnt; j++)
if (i & (1 << j)) continue;
else dp[i + (1 << j)][(k * 10 + num[j]) % m] += dp[i][k]; //状态转移
return dp[(1 << cnt) - 1][0];
//return dfs(cnt, 0, 0);
}
int main() {
n = read(), m = read();
ll ans = solve(n);
for (int i = 0; i <= 9; i++)
for (int j = 1; j <= sum[i]; j++) ans /= j;
//将重复的阶乘除掉
printf("%lld\n", ans);
}