CF401D Roman and Numbers
题意:
将n(n<=10^18)的各位数字重新排列(不允许有前导零) 求 可以构造几个mod m等于0的数字
分析:
状态压缩
状态:
设f[s][k]表示对于选择数字组合的s来说,%m等于k的排列数量。
第一维大小:2^18 第二维大小:100
阶段:
对于s的选择的枚举。s直接从1枚举到1<<(cnt+1) 这样到了s(n)时,所有能转移到s(n)的状态都已经处理完毕。不会有后效性。
由于对于1~n的所有排列,可以考虑是从中选择任意的n-1个数的所有排列,再在最末尾选上剩余的一个数。 所以之后的s(n)所能转移到的最优解,都是与s(n)有关系的(都是通过在s(n)末尾接上一个数转移的),所以满足最优子结构性质。
转移:
对于给定的s,它的18位二进制表示中的每一位是0或者是1表示这一位上的数选择或者不选择。 我们将i从0循环到cnt,(cnt=n的位数-1)想要枚举的是s的每一位1,即枚举出来这个s所选的所有的数的位置,也就知道了所选择的数。
再枚举一下余数j,这样,可以写出这样的状态转移方程:
f[s][(j x 10+w[i])%m]+=f[s^(1<<i)][j]
意义是:每一位的选择都是通过这一位不选择的剩下状态,再把这一位放在末尾组成状态s转移的。
设之前的数为X,X=km+j;
选择了w[i]之后,X=10km+10j+w[i]; 余数就变成了:(10j+w[i])%m
然而有一个缺陷。。。
在于对于有重复数字时,会将一个状态转移从“其实是同一个组合”转移多遍,
举例:n=221 111会从101 转移一次,还会从011转移一次。然而这两个组合其实都是2、1,所以会算重。
所以可以在最后的时候进行多重集合的处理。 也可以每次枚举的时候,判断这一位的值是否之前已经处理过了。
if(vis[w[i]]) continue;
代码:
#include<bits/stdc++.h>
#define ll long long
const int maxs=(<<)+;
const int maxn=;
using namespace std;
int cnt=-,w[],m;
ll f[maxs][maxn],n;
bool vis[];
int main()
{
for(cin>>n>>m;n;n/=)
w[++cnt]=n%;
f[][]=;
for(int s=;s<<<cnt+;s++)
{ memset(vis,,sizeof vis);//注意清空
for(int i=;i<=cnt;i++)
{
if(s==(<<i)&&!w[i]) break;//去掉前导零
if(!(s&(<<i))||vis[w[i]]) continue;//判断是否选择了这一位,并且跳过已经处理过删去w[i]之后转移的情况。
vis[w[i]]=;//标记处理过这个数了。
for(int j=;j<m;j++)
f[s][(j*+w[i])%m]=(f[s][(j*+w[i])%m]+f[s^(<<i)][j]);
}
}
cout<<f[(<<cnt+)-][];//f[11..1][0]
return ;
}
CF401D Roman and Numbers的更多相关文章
- CF401D Roman and Numbers 状压DP
CF401D 题意翻译 将n(n<=10^18)的各位数字重新排列(不允许有前导零) 求 可以构造几个mod m等于0的数字 题目描述 Roman is a young mathematicia ...
- Codeforces Round #235 (Div. 2) D. Roman and Numbers (数位dp、状态压缩)
D. Roman and Numbers time limit per test 4 seconds memory limit per test 512 megabytes input standar ...
- Codeforces Round #235 (Div. 2) D. Roman and Numbers(如压力dp)
Roman and Numbers time limit per test 4 seconds memory limit per test 512 megabytes input standard i ...
- Codeforces Round #235 (Div. 2) D. Roman and Numbers 状压dp+数位dp
题目链接: http://codeforces.com/problemset/problem/401/D D. Roman and Numbers time limit per test4 secon ...
- 题解-Roman and Numbers
题解-Roman and Numbers 前置知识: 数位 \(\texttt{dp}\) </> \(\color{#9933cc}{\texttt{Roman and Numbers} ...
- CF401D 【Roman and Numbers】
题意将n(n<=10^18)的各位数字重新排列(不允许有前导零) 求 可以构造几个mod m等于0的数字解法状压f[S][k] 表示选用的位数集合为S,mod m 为k的方案数注意不能有前导 ...
- Codeforces 401D Roman and Numbers
题目大意 Description 给定一个数 N(N<1018) , 求有多少个经过 N 重组的数是 M(M≤100) 的倍数. 注意: ①重组不能有前导零; ②重组的数相同, 则只能算一个数. ...
- codeforces 401D. Roman and Numbers 数位dp
题目链接 给出一个<1e18的数, 求将他的各个位的数字交换后, 能整除m的数的个数. 用状态压缩记录哪个位置的数字已经被使用了, 具体看代码. #include<bits/stdc++. ...
- [Codefroces401D]Roman and Numbers(状压+数位DP)
题意:给定一个数,求将该数重新排列后mod m==0的方案数 重新排列就考虑到用到哪些数,以及此时mod m的值 于是dp[i][j]表示状态i中mod m==j的方案数 注意:转移的时候只要找到一种 ...
随机推荐
- SQL行转列汇总 (转)
PIVOT 用于将列值旋转为列名(即行转列),在 SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT 的一般语法是:PIVOT(聚合函数(列) FOR 列 in (…) )A ...
- Linux文件下载(转)
wget是Linux最常用的下载命令, 一般的使用方法是: wget + 空格 + 要下载文件的url路径 例如: # wget http://www.linuxsense.org/xxxx/xxx. ...
- 初级Java工程师面试所遇面试题
1.servlet的生命周期 : 一.百度百科 : 1.客户端请求servlet: 2.加载servlet类到内存: 3.实例化并调用init()方法初始化servlet: 4.调用service() ...
- Linux常用指令【转载】
[收藏]Linux常用指令[转载] $ 命令行提示符 粗体表示命令 斜体表示参数 filename, file1, file2 都是文件名.有时文件名有后缀,比如file.zip command 命令 ...
- Linux内核读书笔记第三周 调试
内核调试的难点在于它不能像用户态程序调试那样打断点,随时暂停查看各个变量的状态. 也不能像用户态程序那样崩溃后迅速的重启,恢复初始状态. 用户态程序和内核交互,用户态程序的各种状态,错误等可以由内核来 ...
- 素数问题三步曲_HDOJ2098
偶然间OJ上敲到一题素数问题便查询了相关算法.对于该类问题我个人学习分为三步曲:最笨的方法(TLE毫无疑问)->Eratosthrnes筛选法->欧拉线性筛选法 针对HDOJ2098这道题 ...
- [2017BUAA软工]第零次作业
第一部分:结缘计算机 你为什么选择计算机专业?你认为你的条件如何?和这些博主比呢?(必答) 我当初选择计算机,是因为:1.北航的前辈对北航计算机专业评价非常高:2.我也喜欢通过编程来代替我完成 ...
- PAT L2-015 互评成绩
https://pintia.cn/problem-sets/994805046380707840/problems/994805062432309248 学生互评作业的简单规则是这样定的:每个人的作 ...
- mybatis批量插入和批量更新
批量插入数据使用的sql语句是: insert into table (aa,bb,cc) values(xx,xx,xx),(oo,oo,oo) mybatis中mapper.xml的代码如下: & ...
- php多进程pcntl学习-僵尸进程
上个月写的文章,php多进程pcntl学习(一)现在发现并不完整,因为虽然提到了关闭子进程,但是并没有回收子进程,简单的说就是当子进程比父进程先退出,而父进程没对其做任何处理的时候,子进程将会变成僵尸 ...