题解-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. 七:Redis的持久化

    1.RDB(Redis DataBase) 1.1 定义:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的snapshot快照,他恢复时是将快照文件直接读到内存里 是什么:Redis会单 ...

  2. 动态导航栏和JavaScript箭头函数

    动态导航栏和JavaScript箭头函数 今天我们来写一下动态的导航栏,并且学一下JavaScript的箭头函数等相关问题. 样式如下所示: html中执行代码如下所示: <!DOCTYPE h ...

  3. 2020-11-02(三年之约D92)-优秀不是一种行为,而是一种习惯

    1.阅读:<软技能-代码之外的生存指南>- 第45章 培养习惯:刷新你的代码 成就我们的恰恰就是那些不断重复做的事情.因此,优秀不是一种行为,而是一种习惯--亚里士多德 习惯主要由三个要素 ...

  4. elasticsearch集群安装+安全验证+kibana安装

    准备环境 启动4个centos容器, 并暴露相对应端口 (我的本机ip为172.16.1.236,以下涉及到的地方需要修改为自己的ip) node_name ip http port transpor ...

  5. Matlab项目经验分享-去除震荡点

    Matlab是做科研是比较常用的建模工具,我在研一做项目期间遇到了一个还算比较基础的问题,所以我打算记录下来并分享出来! 处理问题步骤: 1. 抛出问题 2. 思考解决方法 3. 代码验证看结果 抛出 ...

  6. Shodan搜索引擎详解及Python命令行调用

    shodan常用信息搜索命令 shodan配置命令 shodan init T1N3uP0Lyeq5w0wxxxxxxxxxxxxxxx //API设置 shodan信息收集 shodan myip ...

  7. 推荐一款比迅雷下载速度快的mac下载器

    Folx和迅雷是2款支持在Mac系统上进行文件资源下载的工具,两者都支持BT种子资源的下载和直链下载,但Folx还另外支持了下载计划的自定义和智能限速功能.本文主要是为了比较Folx和迅雷在下载同一资 ...

  8. 思维导图软件iMindMap怎么用模板制作思维导图

    随着思维导图的不断发展,市场上相关的软件也越来越多.像XMind.MindManager等.每一款软件都有它独特的亮点.作为众多思维导图软件中的一款,iMindMap算是比较亮眼的了.现在很多人都在用 ...

  9. Elasticsearch搜索资料汇总

    Elasticsearch 简介 Elasticsearch(ES)是一个基于Lucene 构建的开源分布式搜索分析引擎,可以近实时的索引.检索数据.具备高可靠.易使用.社区活跃等特点,在全文检索.日 ...

  10. jquery删除文件

    1 <div class="panel panel-default"> 2 <div class="panel-body"> 3 < ...