BZOJ 1072 排列perm (状压dp)
来源:互联网 发布:算法分析专业 编辑:程序博客网 时间:2024/06/15 16:34
1072: [SCOI2007]排列perm
Time Limit: 10 Sec Memory Limit: 128 MB
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
思路:
s的长度不超过10,算法就大概确定了。
f[i][j]表示选取i状态的数且此时的mod为j。
对于每个状态i,可能从它把的某一个二进制位置为1的位置变为零的状态转移过来(当前选了x个数有a种排列方式使得mod为k,那么在剩下的数字之中任选一个加在排列的最后,那么选x+1个数使得mod为k*10+这个数的值,就多了a种排列方式。代码注释中会解释。),这样不是特别容易操作,所以考虑逆向更新。
dp方程:f[(i|(1<<(k−1)))][(j∗10+a[k])%mod]+=f[i][j];条件是( i&(1<<(k-1)) )==0;
但是如果有重复的数字的话,我们会重复计算,所以除掉重复的数的个数的排列。
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 15#define M 1100using namespace std;int mod, lens, lim;int a[N], cnt[N];char s[N];int f[1<<10][M];//f[i][j]表示选取i状态的数且此时的mod为j//(eg:i=5时,选第1和第3个数,i=9时,选第1和第4个数,i=10时,选第2和第4个数) int J[]={0,1,2,6,24,120,720,5040,40320,362880,3628800};//阶乘 void dfs(){ for(int i=0; i<lim; i++) for(int k=0; k<mod; k++) if( f[i][k] ) for(int j=0; j<lens; j++) if( (i & (1<<j)) == 0 ) f[(i|(1<<j))][(k*10+a[j+1])%mod] += f[i][k];//a[j+1]放在最后 //对于状态i,排列的最后一位可能是选取了的数中的任意一个(前面的排列已经统计好了) //为什么只是加在最后而不是其他地方,因为加在其他地方的情况会在加上它的最后一位的计算中被统计 }int main(){ int T;scanf("%d", &T); while( T-- ){ memset(cnt, 0, sizeof(cnt)); memset(f, 0, sizeof(f)); scanf("%s", s); lens = strlen(s); for(int i=0; i<lens; i++){ a[i+1] = s[i] - '0'; cnt[a[i+1]]++; } scanf("%d", &mod); lim = (1<<lens); f[0][0] = 1; dfs(); int ans = f[lim-1][0];//所有数字用完 for(int i=0; i<=9; i++) if( cnt[i] ) ans /= J[cnt[i]];//相同的数字调换位置本质不变 printf("%d\n", ans); } return 0;}
- BZOJ 1072 排列perm (状压dp)
- BZOJ 1072 SCOI2007 排列perm 状压DP
- BZOJ 1072 [SCOI2007]排列perm 状压DP
- 【BZOJ 1072】 [SCOI2007]排列perm 状压dp
- BZOJ 1072: [SCOI2007]排列perm 状压dp
- bzoj 1072: [SCOI2007]排列perm 状压dp
- BZOJ 1072 [SCOI 2007] 排列perm (状压DP)
- bzoj 1072: [SCOI2007]排列perm(状压DP)
- bzoj 1072: [SCOI2007]排列perm(状压dp)
- BZOJ 1072: [SCOI2007]排列perm 状压DP,暴力全排列
- 【BZOJ 1072】【SCOI 2007】排列perm【状压DP】&【STL】
- 1072: [SCOI2007]排列perm 状压DP
- [BZOJ1072][SCOI2007]排列perm(状压dp)
- [BZOJ1072][SCOI2007]排列perm(状压dp)
- bzoj1072 [SCOI2007]排列perm(状压dp)
- BZOJ 1072: [SCOI2007]排列perm
- bzoj 1072: [SCOI2007]排列perm
- 【BZOJ 1072】 [SCOI2007]排列perm
- 在Visual Studio中使用GitHub(使用篇)
- vue.js为什么不能new两次?不是不能new两次,而是第一次new之后,{{}}已经没有了, 第二次vue的时候,识别不到{{}}了,所以第二次的参数没办法替换了,给人的感觉好像是第二次new不起
- MySQL 常用命令
- SpringBoot集成Swagger
- 用栈模拟递归解不等式
- BZOJ 1072 排列perm (状压dp)
- bzoj3441(线段树的奇怪题)
- UIImage+GIF.swift SDWebImage中处理GIF的分类的swift版实现
- MYSQL ErrorCode:24 too many opened files
- python ConnectionError 或 curl Could not resolve host
- CentOS 6.x安装配置GitLab(社区或个人Git管理)
- 解决ssmdemo项目飘红
- 不通过form表单异步提交
- ios 个人版 开发者账号申请