您的位置:首页 > 其它

light oj 1021 状态压缩dp

2015-08-11 19:40 344 查看
给一个B进制的数,一个10进制的数K,B进制数有x位,对着x位进行全排列的话,有x!种可能,问这x!的可能中,有多少种可以整除K,各个位置上的数字都不同。

代码也是看过题解之后才会写的  QAQ。。。。。。。。

状态压缩dp,每次选一个没有用过的数,然后选一个没有用过的位置放上去,位置不一样,加上的值也不一样,然后直接记录对K取余,余数有多少种。

dp[i][j]表示数位为i(i为1表示数字取了),对K去余为j,有多少种情况。

(j*Base + num[u]) % k,就是表示新组成的数对k去余~

#include <stdio.h>
#include <string.h>
#include <algorithm>
#pragma warning (disable :4996)
using namespace std;

const int Max = 1 << 16;
long long dp[Max][22];

int main()
{
char s[20];
int num[20];
int T;
scanf("%d", &T);
for (int t = 1; t <= T; t++)
{
int base, k;
scanf("%d %d", &base, &k);
scanf("%s", s);
int len = strlen(s);
for (int i = 0; i < len; i++)
{
if (s[i] >= '0'&&s[i] <= '9')
num[i] = s[i] - '0';
else
num[i] = s[i] - 'A' + 10;
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 0; i < (1 << len); i++)//枚举每一位数位
{
for (int j = 0; j <= k; j++)
{
if (!dp[i][j])continue;
for (int u = 0; u < len; u++)
{
if (i&(1 << u))continue;//i在第u个位置上为1,表示被取过了,不进行运算。
dp[i|(1 << u)][(j*base + num[u]) % k] += dp[i][j];
}
}
}
printf("Case %d: %lld\n", t, dp[(1 << len) - 1][0]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: