zoukankan      html  css  js  c++  java
  • 【62.89%】【BZOJ 1072】[SCOI2007]排列perm

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1862  Solved: 1171
    [Submit][Status][Discuss]

    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<=d<=1000, 1<=T<=15

    【题解】

    设f[i][j]表示哪些数字被按顺序放在了前面。i的范围是0..2^10-1. 

    j是按照数字放的顺序组成的十进制数mod d的结果。

    然后我们从小到大枚举状态i。

    然后看看状态i有哪个数字没有被按顺序放下去。

    假设t这个数字没有被放下去。

    就把t这个数字接在前面已经放好顺序的数字后面。

    根据同余律(numpre*10 + t) %k  == 把t接在前面的数字后面组成的数字 % k;

    然后比如这样的

    序列 1 3 5 5 6

    它的不重复排列为 A(5,5)/A(2,2);

    1 3 3 5 5 6

    它的不重复排列为A(6,6)/(A(2,2)*A(2,2));

    所以最后得到的f[2^len - 1][0] 要除(chongfu[i]!) ,i∈[0..9]

    【代码】

    #include <cstdio>
    #include <cstring>
    
    int t;
    char s[15];
    int d,num[15],a[15],len;
    int f[1 << 11][1010],two_n[11],fac[11];
    
    int main()
    {
    	//freopen("F:\rush.txt", "r", stdin);
    	two_n[0] = 1;
    	for (int i = 1; i <= 10; i++)
    		two_n[i] = two_n[i - 1] * 2;//预处理出2^x
    	fac[0] = 1;
    	for (int i = 1; i <= 10; i++)//处理出n!
    		fac[i] = fac[i - 1] * i;
    	scanf("%d", &t);
    	while (t--)
    	{
    		memset(num, 0, sizeof(num));
    		memset(f, 0, sizeof(f));
    		scanf("%s", s);
    		scanf("%d", &d);
    		len = strlen(s);
    		for (int i = 1; i <= len; i++)
    		{
    			a[i] = s[i - 1] - '0';
    			num[a[i]]++;
    		}
    		f[0][0] = 1;
    		for (int i = 0; i <= two_n[len]; i++)
    			for (int k = 0;k <= d-1;k++)
    				for (int j = 1;j <= len;j++)
    					if ((i & two_n[j - 1])== 0)
    						f[i | two_n[j - 1]][(k * 10 + a[j]) % d] += f[i][k];//或运算对于把这个数字加到后面
    		for (int i = 0; i <= 9; i++)
    			f[two_n[len] - 1][0] /= fac[num[i]];
    		printf("%d
    ", f[two_n[len] - 1][0]);
    	}
    	return 0;
    }


  • 相关阅读:
    Do I Have an RNG(Random Number Generator)?
    网页上判断屏幕分辨率
    〖005〗数据监控
    How to use Emerge
    〖006〗开发语言
    Build patched kernel
    GNAP 1.5.1
    五一长假日记(1)
    SQL Server各种日期计算方法
    HOWTO Design your own Framebuffer Splash
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632231.html
Copyright © 2011-2022 走看看