zoukankan      html  css  js  c++  java
  • BZOJ 1072 排列

    Description

    给一个数字串(s)和正整数(d), 统计(s)有多少种不同的排列能被(d)整除(可以有前导(0))。例如(123434)(90)种排列能被(2)整除,其中末位为(2)的有(30)种,末位为(4)的有(60)种。

    Input

    输入第一行是一个整数(T),表示测试数据的个数,以下每行一组(s)(d),中间用空格隔开。(s)保证只包含数字(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).

    Output

    每个数据仅一行,表示能被(d)整除的排列的个数。

    Sample Input

    7
    000 1
    001 1
    1234567890 1
    123434 2
    1234 7
    12345 17
    12345678 29

    Sample Output

    1
    3
    3628800
    90
    3
    6
    1398

    HINT

    在前三个例子中,排列分别有(1, 3, 3628800)种,它们都是(1)的倍数。
    (100\%)的数据满足:(s)的长度不超过(10),$ 1 le d le 1000, 1 le T le 15$

    (f[i][j])表示状态为(i)(用二进制表示,若某位为(1),则该位在排列中)余数为(j)的方案数。于是,我们可以枚举排列长度,利用已知排列进行转移(应该很好YY,脑补一下)。代码应该好理解。

    #include<vector>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    #define maxn (12)
    #define maxm (1010)
    char s[maxn]; int n,m,f[1<<maxn][maxm],mi[maxn],jie[maxn]; vector <int> vec[maxn];
    
    inline void dfs(int now,int bin,int have)
    {
    	if (now > n) { vec[have].push_back(bin); return; }
    	dfs(now+1,bin<<1|1,have+1); dfs(now+1,bin<<1,have);
    }
    
    inline void dp()
    {
    	for (int i = 0;i <= n;++i) vec[i].clear();
    	dfs(1,0,0);
    	mi[0] = 1; 
    	for (int i = 1;i <= n;++i) mi[i] = 10*mi[i-1]%m;
    	memset(f,0,sizeof(f));
    	for (int i = 1;i <= n;++i) f[1<<(i-1)][(s[i]-'0')%m] = 1;
    	for (int i = 2;i <= n;++i)
    	{
    		int ni = vec[i].size();
    		for (int ii = 0;ii < ni;++ii)
    		{
    			int p = vec[i][ii];
    			for (int j = 1;j <= n;++j)
    				if (p & (1<<(j-1)))
    				{
    					int q = p^(1<<(j-1));
    					for (int k = 0;k < m;++k)
    						f[p][(k+mi[i-1]*(s[j]-'0')%m)%m] += f[q][k];
    				}
    		}
    	}
    	for (int i = '0';i <= '9';++i)
    	{
    		int cnt = 0;
    		for (int j = 1;j <= n;++j) cnt += s[j] == i;
    		f[(1<<n)-1][0] /= jie[cnt];
    	}
    }
    
    int main()
    {
    	freopen("1072.in","r",stdin);
    	freopen("1072.out","w",stdout);
    	jie[0] = 1;
    	for (int i = 1;i <= 10;++i) jie[i] = i*jie[i-1];
    	int T; scanf("%d
    ",&T);
    	while (T--)
    	{
    		scanf("%s %d
    ",s+1,&m); n = strlen(s+1);
    		dp(); printf("%d
    ",f[(1<<n)-1][0]);
    	}
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    windows下命令行
    利用border画三角形
    正则
    flex布局
    css笔记
    W3C标准
    SEO相关
    左边固定,右边自适应(解决方案)
    容错性测试的测试点
    Charles安装及使用教程
  • 原文地址:https://www.cnblogs.com/mmlz/p/4299647.html
Copyright © 2011-2022 走看看