题解-Roman and Numbers

前置知识:

数位 \(\texttt{dp}\) </>


\(\color{#9933cc}{\texttt{Roman and Numbers}}\)

给定 \(n\) 和 \(m\),求将 \(n\) 的各位数字重新排列(不允许有前导 \(0\)),求可以构造几个能被 \(m\) 整除。

数据范围:\(1\le n\le 10^{18}\),\(1\le m\le 100\)。


用数位 \(\texttt{dp}\) 代码又短时间又优又好理解,为什么没人玩呢?


把 \(n\) 的各位数字拿出来排序一下,然后把每个数有没有用过状压。

for(;n;n/=10) d.pb(n%10);
sort(d.begin(),d.end()),len=d.size();

选数字的时候只允许用相同数字中第一个没用过的。


\(\texttt{Dfs}\) 中:

  1. \(w\):要找从右往左第几位。
  2. \(st\):当前数字使用状态。
  3. \(sum\):左 \(len-w\) 位数字形成的数 \(\bmod m\) 的余数。
il lng Dfs(re int w,re int st,re int sum){
if(!w) return sum==0;//判断被 m 整除
if(~f[st][sum]) return f[st][sum];
re lng res=0;
for(re int i=0;i<len;i++)
if(!((1<<i)&st)&&(i==0||d[i]!=d[i-1]||((1<<(i-1))&st))) //*
res+=Dfs(w-1,st|(1<<i),(sum*10+d[i])%m);
return f[st][sum]=res; //记忆化,记录答案
}

其中 \(*\) 处的判断:

  1. 该数字未用过。
  2. 该数字前的相同数字都用过。

以保证使用顺序,防止重复统计。

关于 \(f\) 记忆化数组:

现在是 \(f_{st,sum}\),本来应该是 \(f_{w,st,sum}\)。这里就讲讲 \(f_{w,st,sum}\) 记忆化的缺点:

  1. \(1\le w\le 18\),\(1\le st\le 2^{18}\),\(1\le sum<m\le 100\),必然 \(\color{#117}{\texttt{MLE}}\)。
  2. \(st\) 中 \(1\) 的数量 \(cnt\) 必然满足 \(cnt=len-w\),所以只记录 \(st\) 不会重合答案。

时间复杂度 \(\Theta(2^{len}m)\)。


Code

#include <bits/stdc++.h>
using namespace std; //&Start
#define re register
#define il inline
#define mk make_pair
#define pb push_back
#define db double
#define lng long long
#define fi first
#define se second
#define inf 0x3f3f3f3f //&Data
const int W=18,M=100;
int m,len;
lng n,f[1<<W|7][M|7];
vector<int> d; //&Digitdp
il void Pre(){memset(f,-1,sizeof f);}
il lng Dfs(re int w,re int st,re int sum){
if(!w) return sum==0;
if(~f[st][sum]) return f[st][sum];
re lng res=0;
for(re int i=0;i<len;i++)
if(!((1<<i)&st)&&(i==0||d[i]!=d[i-1]||((1<<(i-1))&st)))
res+=Dfs(w-1,st|(1<<i),(sum*10+d[i])%m);
return f[st][sum]=res;
}
il lng DP(){
for(;n;n/=10) d.pb(n%10);
sort(d.begin(),d.end()),len=d.size();
re lng res=0;
for(re int i=0;i<len;i++)
if(d[i]&&(i==0||d[i]!=d[i-1])) // 这里也要判断!这是最容易错的地方
res+=Dfs(len-1,1<<i,d[i]%m);
return res;
} //&Main
int main(){
scanf("%lld%d",&n,&m),Pre();
printf("%lld\n",DP());
return 0;
}

祝大家学习愉快!

题解-Roman and Numbers的更多相关文章

  1. 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 ...

  2. 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 ...

  3. 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 ...

  4. [LeetCode 题解]: Add Two Numbers

    You are given two linked lists representing two non-negative numbers. The digits are stored in rever ...

  5. [LeetCode 题解]: Roman to Interger

    前言   [LeetCode 题解]系列传送门:  http://www.cnblogs.com/double-win/category/573499.html   1.题目描述 Given a ro ...

  6. CF401D Roman and Numbers 状压DP

    CF401D 题意翻译 将n(n<=10^18)的各位数字重新排列(不允许有前导零) 求 可以构造几个mod m等于0的数字 题目描述 Roman is a young mathematicia ...

  7. leetcode 题解 Add Two Numbers(两个单链表求和)

    题目: You are given two linked lists representing two non-negative numbers. The digits are stored in r ...

  8. Codeforces 401D Roman and Numbers

    题目大意 Description 给定一个数 N(N<1018) , 求有多少个经过 N 重组的数是 M(M≤100) 的倍数. 注意: ①重组不能有前导零; ②重组的数相同, 则只能算一个数. ...

  9. LeetCode题解——Roman to Integer

    题目: 将罗马数字转换为整数. 解法: 可以参考上一篇数字转换为罗马数字的规则. 代码: class Solution { public: int sym2int(char sym) //罗马数字字符 ...

随机推荐

  1. MySQL时间类型datetime、bigint及timestamp的查询效率

    前期数据准备 通过程序往数据库插入 50w 数据 数据表: CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `time_dat ...

  2. AHB SRAM控制器设计

  3. python之《set》

    set 是python里面的集合的概念 list_1 = [1,2,3,4,5,6,] list_2 = set(list_1) print(list_1,type(list_1)) print(li ...

  4. mysql8.0参考手册学习

    mysql8.0参考手册链接:https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-join-ord ...

  5. ceph集群的安装和配置教程

    本篇主题: 1.怎样配置ssh免登陆访问 2.为什么搭建集群要关闭防火墙和selinux,如何关闭 3.从哪里获取ceph的安装包,怎样安装才是快速正确的 4.为什么要配置时间同步服务,怎样配置 5. ...

  6. 打乱Map key - value的对应顺序

    应用场景:对于考试试卷选择题选项的乱序对应问题,防止考生作弊,每个人的题目都是不一样的选项顺序. package com.muyuan.platform.elearning.util; import ...

  7. Elasticsearch 国内镜像下载站

    镜像地址:https://thans.cn/mirror/elasticsearch.html 支持 5.0.0~7.3.1 各个平台的各个版本. 本文章转载他人.

  8. php(tp5)实现分页效果

    public function admin(){ if(request()->isPost()){ //获取第二页的数据传current = 2过来即可 $post['origin'] = in ...

  9. 死磕以太坊源码分析之p2p节点发现

    死磕以太坊源码分析之p2p节点发现 在阅读节点发现源码之前必须要理解kadmilia算法,可以参考:KAD算法详解. 节点发现概述 节点发现,使本地节点得知其他节点的信息,进而加入到p2p网络中. 以 ...

  10. DNS系列—dig命令的使用

    目录 如何安装dig dig常见用法 dig的基本语法 简单dig查询域名 指定DNS服务器查询 反查IP对应域名 如何安装dig dig是bind下面常见的工具,在linux系统上经常回用的一个dn ...