暑假集训Day 4 P4163 [SCOI2007]排列 (状压dp)
状压dp
(看到s的长度不超过10就很容易想到是状压dp了
但是这个题的状态转移方程比较特殊)
题目大意
给一个数字串 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 整除的排列的个数。
输入样例
7
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29
输出样例
1
3
3628800
90
3
6
1398
算法分析
- 这个题的思路还是蛮偏的,,,,但是很好理解
我们将f数组的第一维定义为状态 (最大值为1<<10) 第二维定义为 余数
那么问题就来了 如果我们把第一维定义为状态的话 应该是怎样的状态呢?
还是一样举个栗子:
给出的数为1234 我们就定义一个1<<4大小的状态 然后每一位表示对应该位置的数是否已经添加
比如0101就表示此时我们已经添加了2和4还有1和3没有添加进去 下一次可以选择添加进去1或者3 - 循环顺序
第一层循环状态 第二层循环余数 第三层循环下一个添加的数字
则转移方程就是f[i|1<<k][(j * 10+k)%d] += f[i][j]
第一维是i|1<<k 显然就是加上k位置的数字
第二维是(j * 10+k)%d 即上一位的余数再加上当前位 然后整个再%d
*转移条件
如果当前状态向下个状态转移的时候 即加上第k位置数字 这个已经转移过了 那么显然就不能再加一次了
判断语句就是
if((i & (1<<k)) == 0)
此时状态为i 想要转移的状态为i|1<<k 如果i&1<<k != 0 即表示i在第k位为1 也就是表示这个状态已经转移过了 所以要保证==0的时候再转移
- 需要注意有的数字是重复的 显然根据排列组合的规律 除以这个重复数字的全排列即可 即除以该数的阶乘(可以预处理或者写个函数 这里提供函数的代码)
代码展示
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int f[1<<10][1001],T,a[maxn],d,cnt[11];
char s[maxn];
int jc(int x){
int u = 1;
for(int i = 1;i <= x;++i)u *= i;
return u;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%s%d",s,&d);
int len = strlen(s);
memset(cnt,0,sizeof(cnt));
memset(f,0,sizeof(f));
for(int i = 0;i < len;++i){
a[i] = s[i] - '0';
cnt[a[i]]++;
}
int maxs = (1<<len)-1;
f[0][0] = 1;
for(int i = 0;i <= maxs;++i){
for(int j = 0;j < d;++j)
if(f[i][j])
for(int k = 0;k < len;++k)
if((i & (1<<k)) == 0)
f[i|(1<<k)][(j*10+a[k])%d] += f[i][j];
}
int ans = f[maxs][0];
for(int i = 0;i <= 9;++i){
if(cnt[i]!=0)ans/=jc(cnt[i]);
}
printf("%d\n",ans);
}
return 0;
}
谢谢观看
点个关注>)<
暑假集训Day 4 P4163 [SCOI2007]排列 (状压dp)的更多相关文章
- 【BZOJ1072】【SCOI2007】排列 [状压DP]
排列 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 给一个数字串s和正整数d, 统计s有多 ...
- LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp
这个题的搜索可以打到48分…… #include <cstdio> #include <cstring> #include <algorithm> ; bool m ...
- P4163 [SCOI2007]排列——next_permutation
P4163 [SCOI2007]排列 注意要排序: next_permutation prev_permutation #include<cstdio> #include<cstri ...
- 暑假集训Day2 互不侵犯(状压dp)
这又是个状压dp (大型自闭现场) 题目大意: 在N*N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. ...
- [BZOJ 1072] [SCOI2007] 排列perm 【状压DP】
题目链接:BZOJ 1072 这道题使用 C++ STL 的 next_permutation() 函数直接暴力就可以AC .(使用 Set 判断是否重复) 代码如下: #include <io ...
- B1072 [SCOI2007]排列perm 状压dp
很简单的状压dp,但是有一个事,就是...我数组开大了一点,然后每次memset就会T,然后开小就好了!!!震惊!以后小心点这个问题. 题干: Description 给一个数字串s和正整数d, 统计 ...
- LUOGU P4163 [SCOI2007]排列
传送门 解题思路 首先我们发现这道题s的长度很小,所以考虑点暴力的做法,状压dp或搜索.本蒟蒻搜索永远调不对,所以就写了个状压dp.因为所有s里的数都要出现一次,并且最后的答案是要求整除,那么我们设d ...
- 暑假集训 || 状压DP
emm 位操作实现技巧: 获得第i位的数据: if(!(data & (1<< i))) 则data的第 i 位为0,else 为 1 设置第i位为1,data=(data | ...
- 暑假集训Day2 状压dp 特殊方格棋盘
首先声明 : 这是个很easy的题 可这和我会做有什么关系 题目大意: 在n*n的方格棋盘上放置n个车,某些格子不能放,求使它们不能互相攻击的方案总数. 注意:同一行或同一列只能有一个车,否则会相互攻 ...
随机推荐
- 2019-ICLR-DARTS: Differentiable Architecture Search-论文阅读
DARTS 2019-ICLR-DARTS Differentiable Architecture Search Hanxiao Liu.Karen Simonyan.Yiming Yang GitH ...
- 居然还有人这样解说mybatis运行原理
目录 Mybatis基本认识 动态代理 JDK实现 CGLIB动态代理 总结 反射 Configuration对象作用 映射器结构 sqlsession执行流程(源码跟踪) Executor Stat ...
- Java实现 LeetCode 649 Dota2 参议院(暴力大法)
649. Dota2 参议院 Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇) Dota2 参议院由来自两派的参议员组成.现在参议院希望对一个 Dota2 游戏里的改变作出决 ...
- Java实现 LeetCode 605 种花问题(边界问题)
605. 种花问题 假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有.可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去. 给定一个花坛(表示为一个数组包含0和1,其中0表示没种 ...
- Java中那些烦人的位运算(&,|...)
& 和 && 相同点: 都表示"与"操作.这里的"与"和数学中的"与或非"中的"与"意义相同,都 ...
- Java实现大整数乘法
1 问题描述 计算两个大整数相乘的结果. 2 解决方案 2.1 蛮力法 package com.liuzhen.chapter5; import java.math.BigInteger; publi ...
- java实现第四届蓝桥杯振兴中华
振兴中华 题目描述 小明参加了学校的趣味运动会,其中的一个项目是:跳格子. 地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg) 从我做起振 我做起振兴 做起振兴中 起振兴中华 比 ...
- java代码(3)----guava复写Object常用方法
guava复写Object常用方法 Guava是一个Google的基于java1.6的类库集合的扩展项目,这个库提供用于集合,缓存,支持原语,并发性,字符串处理,I/O和验证的实用方法, 这些高质量的 ...
- PAT 旧键盘打字
旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在 2 行中分别给出坏掉的那些键.以及应该输入 ...
- 1.Go 开始搞起
link 1. IDE Go Land 服务器激活 2. 资源 中文网站 翻译组 翻译组wiki 待认领文章 入门指南 中文文档 fork 更新 github 中如何定期使用项目仓库内容更新自己 fo ...