同时考验对状压DP和数位DP的理解;

传送门:$>here<$

题意

给出一个数字$e$,现在对$e$通过$m$进行变换得到$x$;变换的要求是:1.只能改变原数字$e$各个数位的顺序(可以有前导零) 2.$x$是$m$的倍数 3. $x<e$

问$x$有几种取值满足?

数据范围:$e \leq 10^14, m \leq 20$

Solution

DFS怎么做是关键

这道题如果使用DFS,那么大体思路就是枚举每一位填放什么数字。

那么需要一个数组(状压)在此过程中来记录还可以用哪些数字。这个地方不要想太多,我起初的思路刚开始统计一格数组代表0~9每个数字有几个,再依次减。然而这样麻烦,而且无法状压。一个直接的思路是直接用一个布尔数组表示原数组的每一位是否被用掉。

光这样是不行的,我们忘记考虑重复问题了。即$e=422$时,枚举每一位填什么时程序会把每个数字看成不同的,也就会出现$224,242,224,242$四种情况。

解决重复问题

如果按照我刚开始的思路把0~9各位统计出来就没这样的问题了。于是考虑能不能在状压的情况下也能达成这种效果。把$e$中各位进行排序得到$num$数组。这样的话,每当我使用一个数字的时候,先去检查在它之前的相同数字是否已被使用完——相当于把每种数字弄成一个栈,每次只能取栈顶。

转化为程序语言,就是满足一下三个条件中的一个:

1. 当前数字是$num$中的首个(特判第一个数字的栈顶)

2. 当前数字与前面那个数字不同(还未使用过的某个数字的栈顶)

3. 当前数字前面的那个已被用过(使用过的某个数字的栈顶)

目前为止,复杂度是阶乘

与数位DP相结合

找到刚才问题中的子结构——当还有哪些数字可以用确定时,只要知道之前数字的大小以及模m的情况即可了。

所谓数字的大小,就是在搜索的过程中保证搜出来的结果要小于e。之前学数位DP的时候已经强调过了,这也是数位DP的一个精髓思想:如果先前的数字已经较e的高位较小了,那么后面的数字可以任意填(无论如何不会超出e)。如果之前刚好与e一样,那么后面的依然要小心不超出。

透过题解看本质

状压解决顺序问题

当数据范围是十几,需要解决顺序问题时,往往采用状压

关于题中的重复问题

这题相较于一般的数位DP在于能使用的数的限制。却又要保证不重复,因此保证数字像栈一样使用的思路很重要,需要反复琢磨吧……

my code

代码的细节也是个大问题,严格区分cur和i——一个是递归中指示第几层的变量,一个是循环变量。

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9+;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = ; int w = ; register char c = getchar();
for(; c ^ '-' && (c < '' || c > ''); c = getchar());
if(c == '-') w = -, c = getchar();
for(; c >= '' && c <= ''; c = getchar()) x = (x<<) + (x<<) + c - ''; return x * w;
}
char s[];
int T,m,len,digit[],num[],e[],dp[][][];
int dfs(int cur, int sta, int mo, bool lim){
if(cur == len){
if(mo== && lim==){
return ;
}
else{
return ;
}
}
int& a = dp[sta][mo][lim];
if(a != -) return a;
a = ;
for(int i = ; i < len; ++i){
if(lim && num[i] > e[cur]) break;
if(sta & (<<i)) continue;
if(i== || num[i]!=num[i-] || (sta & (<<(i-)))){
digit[cur] = num[i];
a = (a + dfs(cur+, sta|(<<i), (mo*+num[i])%m, lim&(num[i]==e[cur]))) % MOD;
}
}
return a;
}
int main(){
scanf("%d",&T);
while(T--){
memset(dp,-,sizeof(dp));
memset(digit,,sizeof(digit));
scanf("%s",s);
scanf("%d",&m);
len = strlen(s);
for(int i = ; i < len; ++i){
e[i] = s[i] - '';
num[i] = e[i];
}
sort(num,num+len);
printf("%d\n",dfs(,,,));
}
return ;
}

「Algospot」津巴布韦ZIMBABWE的更多相关文章

  1. 「Algospot」龙曲线DRAGON

    一道考验思维的好题,顺便总结求第k大问题的常规思路: 传送门:$>here<$ 题意 给出初始串FX,每分形一次所有X替换为X+YF,所有Y替换为FX-Y.问$n$代字符串第$p$位起长度 ...

  2. 「Algospot」量化QUANTIZE

    一道不难的DP题,主要是为了总结这类最优化题的思路:同时还学到了一个新操作 传送门:$>here<$ 题意 给出一个长度为$N$的序列,要求最多使用s个数字进行量化(有损压缩),即代替原数 ...

  3. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  4. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  5. JavaScript OOP 之「创建对象」

    工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...

  6. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

  7. 「JavaScript」四种跨域方式详解

    超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...

  8. 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management

    写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...

  9. 「2014-3-18」multi-pattern string match using aho-corasick

    我是擅(倾)长(向)把一篇文章写成杂文的.毕竟,写博客记录生活点滴,比不得发 paper,要求字斟句酌八股结构到位:风格偏杂文一点,也是没人拒稿的.这么说来,arxiv 就好比是 paper 世界的博 ...

随机推荐

  1. 第三节:dingo/API 最新版 V2.0 之 Creating API Endpoints (连载)

    对于这篇文章的标题,其实,直译就是创建api端点.但是,真的很难懂,我还是写为API路由吧.每篇,文章,我都会全部去进行实践操作,力求写一个好点的教程. 本文英文地址——>https://git ...

  2. 兼容小程序的canvas画图组件jmGraph

    基于CANVAS的简单画图组件让你用类似于dom的方式,在canvas上画图,感觉会不会很爽. 主页:http://graph.jm47.com/示例:http://graph.jm47.com/ex ...

  3. java之servlet入门操作教程一

    这篇文章主要用来记录,进行servlet开发的一些简单操作步骤,帮助直接上手操作 准备: java环境配置:已配置(javac检验) myeclipse开发环境:已安装 tomcat服务器:已安装(或 ...

  4. C# 绘制PDF嵌套表格

    嵌套表格,即在一张表格中的特定单元格中再插入一个或者多个表格,使用嵌套表格的优点在于能够让内容的布局更加合理,同时也方便程序套用.下面的示例中,将介绍如何通过C#编程来演示如何插入嵌套表格到PDF文档 ...

  5. 2018/1.6 Javascript 继承和克隆

    这种写法不是对象克隆,就是把obj的内存地址赋给obj2 通过 for in 克隆 不管公有还是私有的都克隆成私有的. js提供了一个克隆方法 objct.create() var obj2=obje ...

  6. nginx系列11:负载均衡哈希算法ip_hash与hash模块

    使用默认的round-robin负载均衡算法无法保证某一类请求只能由上游的某一台应用服务器处理,它只适用于AKF扩展中的水平扩展,如果要保证某一类请求只能由上游的某一台应用服务器处理,就需要用到AKF ...

  7. JavaScript常用代码书写规范

    javascript 代码规范 代码规范我们应该遵循古老的原则:“能做并不意味着应该做”. 全局命名空间污染 总是将代码包裹在一个立即的函数表达式里面,形成一个独立的模块. 不推荐 , y = ; c ...

  8. react+redux+Instagram

    项目地址:https://github.com/xiaoyuqing/react-redux-instagram,喜欢的话动动手指点点赞^-^ 1.初始化项目 IndexRoute是默认路由 2.增加 ...

  9. Android设计模式总结

    1.复合模式:三层架构.MVC.MVP.MVVM 2.设计模式-单例模式 配置类的使用. 3.设计模式-模板方法 通过抽象类或接口提前定义要实现的方法. 4.设计模式-观察者模式 消息的通知. 5.设 ...

  10. TTL与非门电路分析

    TTL与非门(TTL推挽式与非门)是TTL集成逻辑门的一种,主要由三极管和二极管构成.如图(a)所示,它由输入级,中间级,输出级三部分组成.TTL与非门的优点在于输出阻抗低,带负载能力强,工作速度快. ...