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

 
 

题解

暴力可以过,但状压dp才是正解。
 
设f[s][j]表示状态s下【s表示已经选择了哪些数】余数为j的方案数,那么f[s | (1<<i-1)][(j * 10 + a[i])%d] += f[s][j]
很明显,状态s下可以通过在末尾添加一个不在状态中的i号数来转移到s|(1<<i-1)这个状态
 
设立一个状态(突然不知道怎么用语言描述这个状态)DP(I,J),IDP(I,J),I表示当前枚举的状态,JJ表示状态I对应的数字的数值,这样设立状态后很容易得出下面的状态转移方程: 
 

其中判断语句的含义是在II状态中,KK号没有选择出来。

状态转移结束后,由于数串中可能存在重复的数字(样例已经给出来了),这个时候我们就会有许多重复的计算。这个问题很好解决,我们根据排列的知识将最后的Ans/=Cnt[I] Cnt[I] 记录数字I在数串中出现的次数)就可以了。

C++代码/暴力

#include<bits/stdc++.h>
using namespace std;
int a[],b[];
int n ,d;
int ans ;
void dfs(int i,long long x){
if(i > n){ if(x % d == ) ans ++;
return;
}
for(int j = ;j <= ;j ++){
if(b[j]) {
--b[j];
dfs(i + ,x * + j);
++b[j];
}
}
} int main(){
int t;
cin >> t;
while(t--){
string str;
cin >> str;
ans = ;
n = str.size();
memset(a,,sizeof a);
memset(b,,sizeof b);
for(int i = ; i < str.size() ; i++){
a[i] = str[i] - '';
b[a[i]]++;
}
cin >> d;
dfs(,);
cout << ans << endl;
}
}

C++代码/状压

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define DB double
#define SG string
#define LL long long
#define DP(A,B) DP[A][B]
#define Fp(A,B,C,D) for(A=B;A<=C;A+=D)
#define Fm(A,B,C,D) for(A=B;A>=C;A-=D)
#define Clear(A) memset(A,0,sizeof(A))
using namespace std;
const LL Mod=1e9+;
const LL Max=2e3+;
const LL Inf=1e18;
LL T,M,Num[Max],Cnt[Max],DP[Max][Max];
inline LL Read(){
LL X=;char CH=getchar();bool F=;
while(CH>''||CH<''){if(CH=='-')F=;CH=getchar();}
while(CH>=''&&CH<=''){X=(X<<)+(X<<)+CH-'';CH=getchar();}
return F?-X:X;
}
inline void Write(LL X){
if(X<)X=-X,putchar('-');
if(X>)Write(X/);
putchar(X%+);
}
int main(){
LL I,J,K,L;
T=Read();
while(T--){
Clear(Cnt);Clear(DP);
char CH[];scanf("%s",CH+);
LL Length=strlen(CH+);M=Read();
Fp(I,,Length,){
Num[I]=CH[I]-'';
Cnt[Num[I]]++;
}DP(,)=;
K=(<<Length)-;
Fp(I,,K,){
Fp(J,,M-,){
Fp(L,,Length,){
if((I&(<<(L-)))==){
DP(I|(<<(L-)),((J<<)+(J<<)+Num[L])%M)+=DP(I,J);
}
}
}
}LL Ans=DP(K,);
Fp(I,,,){
Fp(J,,Cnt[I],){
Ans/=J;
}
}Write(Ans);putchar('\n');
}
return ;
}

排列perm HYSBZ - 1072(状压dp/暴力)的更多相关文章

  1. N - 寿司晚宴 HYSBZ - 4197 状压dp

    N - 寿司晚宴 HYSBZ - 4197 推荐题解 这个题目我觉得还是很难的,借助题解写出来的,题解还看了很久,现在还是不是很理解. 首先这个数比较大有500,如果直接就像这个题目S - Query ...

  2. bzoj 1072状压DP

    1072: [SCOI2007]排列perm Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2293  Solved: 1448[Submit][St ...

  3. bzoj 1072 状压DP

    我们用w[i][j]来表示,i是一个二进制表示我们选取了s中的某些位,j表示这些位%d为j,w[i][j]则表示这样情况下的方案数,那么我们可以得到转移.w[i|(1<<k)][(j*10 ...

  4. K - Painful Bases 状压dp

    Painful Bases LightOJ - 1021 这个题目一开始看,感觉有点像数位dp,但是因为是最多有16进制,因为限制了每一个数字都不同最多就有16个数. 所以可以用状压dp,看网上题解是 ...

  5. [BZOJ 1072] [SCOI2007] 排列perm 【状压DP】

    题目链接:BZOJ 1072 这道题使用 C++ STL 的 next_permutation() 函数直接暴力就可以AC .(使用 Set 判断是否重复) 代码如下: #include <io ...

  6. 「状压DP」「暴力搜索」排列perm

    「状压DP」「暴力搜索」排列 题目描述: 题目描述 给一个数字串 s 和正整数 d, 统计 sss 有多少种不同的排列能被 d 整除(可以有前导 0).例如 123434 有 90 种排列能被 2 整 ...

  7. BZOJ1072 排列perm 【状压dp】

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

  8. B1072 [SCOI2007]排列perm 状压dp

    很简单的状压dp,但是有一个事,就是...我数组开大了一点,然后每次memset就会T,然后开小就好了!!!震惊!以后小心点这个问题. 题干: Description 给一个数字串s和正整数d, 统计 ...

  9. CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

    问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...

随机推荐

  1. registry搭建及镜像管理

    registry 的搭建 docker pull registry:2 docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 -- ...

  2. Spring Data Jpa (二)JPA基础查询

    介绍Spring Data Common里面的公用基本方法 (1)Spring Data Common的Repository Repository位于Spring Data Common的lib里面, ...

  3. Mongodb分片副本集集群搭建

    一.环境准备 1.1.主机信息(机器配置要求见硬件及开发标准规范文档V1.0) 序号 主机名 IP 1 DB_01 10.202.105.52 2 DB_02 10.202.105.53 3 DB_0 ...

  4. insert和insertSelective区别

    两者的区别在于如果选择insert 那么所有的字段都会添加一遍即使没有值 <insert id="insert" parameterType="com.ego.po ...

  5. LeetCode_509.斐波那契数

    LeetCode-cn_509 509.斐波那契数 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列.该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) ...

  6. KVM 常用命令

    显示虚拟机 virsh list --all 停止虚拟机 virsh destroy <name> 启动虚拟机 virsh start <name> 删除虚拟机 virsh u ...

  7. leetcode-mid-sorting and searching-162. Find Peak Element

    mycode  54.81% class Solution(object): def findPeakElement(self, nums): """ :type num ...

  8. 中国MOOC_零基础学Java语言_第3周 循环_2数字特征值

    2 数字特征值(5分) 题目内容: 对数字求特征值是常用的编码算法,奇偶特征是一种简单的特征值.对于一个整数,从个位开始对每一位数字编号,个位是1号,十位是2号,以此类推.这个整数在第n位上的数字记作 ...

  9. postman杂记

    接到测试任务,测试6个接口 rap2 上的接口比较多,整体导出内容太多 就一个接口一个接口的,复制到了postman上 rap2部分接口,开发没有备注简介内容:通知开发备注下 对接口的理解,还是靠功能 ...

  10. Cocos2d-X网络编程(3) Cocos2d中的网络通信协议——WebSocket协议

    WebSocket protocol 是HTML5一种新的协议.它实现了浏览器与服务器全双工通信.实现浏览器与服务器的即时通讯.即服务器也能主动向客户端发消息. WebSocket代理类和方法: co ...