卧薪尝胆,厚积薄发。
SCOI2007 排列
Date: Wed Sep 05 08:27:33 CST 2018
In Category:
NoCategory
Description:
给一个数字串
$s$
和一个数字
$d$
,计算
$s$
有多少种不同的排列能被
$d$
整除,可以有前导零。
$1\le len_s\le 10,1\le d \le 1000$
Solution:
$s$
长度只有
$10$
可以状压,
$f[i][j]$
表示已经选的状态是
$i$
,对
$d$
取模余数是
$j$
的方案数。转移直接枚举最后一位填哪个,注意如果这个数字已经选过就不能再选。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int f[1050][1010];
char c[12];
int m;
bool v[10];
void work()
{
scanf("%s",c + 1);scanf("%d",&m);
int n = strlen(c + 1);
for(int i = 1;i <= n;++i)c[i] -= '0';
int tot = (1 << n) - 1;
memset(f,0,sizeof(f));
f[0][0] = 1;
for(int b = 0;b <= tot;++b)
{
memset(v,false,sizeof(v));
for(int i = 1;i <= n;++i)
{
if(b & (1 << (i - 1)))continue;
if(v[c[i]])continue;
for(int k = 0;k < m;++k)
{
f[b | (1 << (i - 1))][(k * 10 + c[i]) % m] += f[b][k];
}
v[c[i]] = true;
}
}
cout << f[tot][0] << endl;
return;
}
int main()
{
int testcases;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}
In tag:
DP-状压DP
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡