标签:一个 输入输出格式 temp += 经典 memset 超过 阶乘 输出
题目描述
给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0)。例如123434有90种排列能
被2整除,其中末位为2的有30种,末位为4的有60种。
输入输出格式
输入格式:
输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开。s保证只包含数字0, 1
, 2, 3, 4, 5, 6, 7, 8, 9.
输出格式:
每个数据仅一行,表示能被d整除的排列的个数。
输入输出样例
输入样例#1:
7
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29
输出样例#1:
1
3
3628800
90
3
6
1398
100%的数据满足:s的长度不超过10, 1<=d<=1000, 1<=T<=15.
状压dp经典题,用\(f(S, j)\)表示用了集合S中的点,现在余数是j的方案数.
转移比较容易:\(f(S \cup i, (k * 10 + s_i)\mod d) += f(S, k)\)
最后解决重复,除以\(0\)~\(9\)每个数出现次数的阶乘就行啦.
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
namespace INPUT {
const int L = 1 << 15;
char _buf[L], *S, *T, c;
char _gc() {
if(S == T) {
T = (S=_buf) + fread(_buf, 1, L, stdin);
if(S == T) return EOF;
}
return *S ++;
}
template<typename T> void write(T x) {
if(x < 0) x = -x, putchar('-');
static char buf[31];
int p(0);
do buf[p ++] = x % 10 + '0', x /= 10;
while(x);
for(int i=p-1; ~i; i--) putchar(buf[i]);
}
template<typename T> T Read() {
T ans(0);
bool Sign = false;
while(!isdigit(c = _gc()) && c != '-');
if(c == '-') Sign = true, c = _gc();
do ans = ans * 10 + c - 48;
while(isdigit(c=_gc()));
return Sign ? -ans : ans;
}
};
using namespace INPUT;
#define MAXN 10
#define MAXD 1000
int f[1 << MAXN][MAXD], s[MAXN], d, n, ans;
int cl[MAXN + 1], fc[MAXN + 1];
void Init_fc() {
fc[0] = 1;
for(int i=1; i<=MAXN; i++)
fc[i] = fc[i-1] * i;
}
int main() {
Init_fc();
int T = Read<int>(), ans;
while(T --) {
while(!isdigit(c = _gc())) ;
for(n = 0; isdigit(c); c = _gc()) s[n ++] = c - '0';
d = Read<int>();
memset(f, 0, sizeof f);
f[0][0] = 1;
for(int S=0; S<1<<n; S ++) {
for(int k=0; k<d; k++) if(f[S][k])
for(int i=0; i<n; i++) if(!(S & 1 << i))
f[S | 1 << i][(k * 10 + s[i]) % d] += f[S][k];
}
ans = f[(1<<n)-1][0];
memset(cl, 0, sizeof cl);
for(int i=0; i<n; i++) cl[s[i]] ++;
for(int i=0; i<10; i++) ans /= fc[cl[i]];
write<int>(ans);
putchar('\n');
}
return 0;
}
标签:一个 输入输出格式 temp += 经典 memset 超过 阶乘 输出
原文地址:https://www.cnblogs.com/cute-hzy/p/9325166.html