CF401D. Roman and Numbers

题目大意:

  将一个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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值