D. Roman and Numbers
time limit per test

4 seconds

memory limit per test

512 megabytes

input

standard input

output

standard output

Roman is a young mathematician, very famous in Uzhland. Unfortunately, Sereja doesn't think so. To make Sereja change his mind, Roman is ready to solve any mathematical problem. After some thought, Sereja asked Roma to find, how many numbers are close to number n,
modulo m.

Number x is considered close to number n modulo m,
if:

  • it can be obtained by rearranging the digits of number n,
  • it doesn't have any leading zeroes,
  • the remainder after dividing number x by m equals
    0.

Roman is a good mathematician, but the number of such numbers is too huge for him. So he asks you to help him.

Input

The first line contains two integers: n (1 ≤ n < 1018) and m (1 ≤ m ≤ 100).

Output

In a single line print a single integer — the number of numbers close to number n modulo m.

Sample test(s)
input
104 2
output
3
input
223 4
output
1
input
7067678 8
output
47
Note

In the first sample the required numbers are: 104, 140, 410.

In the second sample the required number is 232.

题意:

给定一个数字n。将n的每一位数字又一次排列,求在这些排列数之中能够被n整除的方法数。

思路1:

数位dp。数字仅仅有18位,能够考虑位压缩。

dp[i][j]表示状态所用的状态为i。前缀模m余j的个数。

枚举下一位选哪一个数来进行状态转移。

用记忆化搜索来实现。注意不能有前导0。

如何解决不反复计算呢,採用的方法是每次转移的时候不反复转移,用一个数组vis[10]来标记选了什么,比方计

算了3之后,后面还有3就不选了,就不会计算反复了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 205
#define MAXN 100005
#define mod 100000000
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std; ll n,m,ans,tot,ed;
ll dig[20],dp[1<<18][105]; ll dfs(ll s,ll sy,ll flag)
{
if(s==ed)
{
if(sy==0) return 1;
return 0;
}
if(dp[s][sy]!=-1) return dp[s][sy];
ll i,t,best=0;
bool vis[10]={0};
for(i=0;i<tot;i++)
{
if(vis[dig[i]]||(s&(1<<i))) continue ;
if(flag==0&&dig[i]==0) continue ;
ll ss=s|(1<<i),ty=(sy*10+dig[i])%m;
vis[dig[i]]=1;
best+=dfs(ss,ty,1);
}
dp[s][sy]=best;
return best;
}
void solve()
{
ll i,j,t,x;
x=n;
memset(dig,0,sizeof(dig));
memset(dp,-1,sizeof(dp));
tot=0;
while(x)
{
t=x%10;
dig[tot++]=t;
x/=10;
}
ed=(1<<tot)-1;
ans=dfs(0,0,0);
}
int main()
{
ll i,j,t;
while(~scanf("%I64d%I64d",&n,&m))
{
solve();
printf("%I64d\n",ans);
}
return 0;
}

思路2:

学习了一种新的状压方式,来源于德保

直接依据数码x出现的次数进行状态压缩。比方33211就仅仅须要2*6+1*3+2=17的空间了。利用均值不等式。也差点儿相同仅仅需(ceil(18/10+1)^10)=59049的空间。

并且这样能够用递推来实现。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 205
#define MAXN 100005
#define mod 100000000
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std; ll n,m,ans,tot;
ll dig[10],dp[60000][105]; ll codeit(ll tmp[]) // 状态压缩
{
ll i,t=0;
for(i=0; i<10; i++)
{
t=t*(dig[i]+1)+tmp[i];
}
return t;
}
void decode(ll s,ll tmp[]) // 从压缩状态中解码 还原状态
{
ll i,t;
for(i=9; i>=0; i--)
{
tmp[i]=s%(dig[i]+1);
s/=(dig[i]+1);
}
}
void solve()
{
ll i,j,t,x=n;
memset(dig,0,sizeof(dig));
while(x)
{
dig[x%10]++;
x/=10;
}
tot=codeit(dig);
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(i=0; i<=tot; i++)
{
ll cnt[10];
decode(i,cnt); // 解码
for(ll k=0; k<10; k++) // 枚举下一位
{
if(cnt[k]>=dig[k]) continue ;
if(i==0&&k==0) continue ;
cnt[k]++;
ll s=codeit(cnt); // 状态压缩
for(j=0; j<m; j++) // 枚举余数
{
dp[s][(j*10+k)%m]+=dp[i][j]; // 转移
}
cnt[k]--;
}
}
ans=dp[tot][0];
}
int main()
{
ll i,j,t;
while(cin>>n>>m)
{
solve();
cout<<ans<<endl;
}
return 0;
}

Codeforces Round #235 (Div. 2) D. Roman and Numbers (数位dp、状态压缩)的更多相关文章

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

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

  3. Codeforces Round #287 (Div. 2) D. The Maths Lecture [数位dp]

    传送门 D. The Maths Lecture time limit per test 1 second memory limit per test 256 megabytes input stan ...

  4. BestCoder Round #52 (div.2) HDU 5418 Victor and World (DP+状态压缩)

    [题目链接]:pid=5418">click here~~ [题目大意]: 问题描写叙述 经过多年的努力,Victor最终考到了飞行驾照. 为了庆祝这件事,他决定给自己买一架飞机然后环 ...

  5. Codeforces Round #267 (Div. 2) C. George and Job(DP)补题

    Codeforces Round #267 (Div. 2) C. George and Job题目链接请点击~ The new ITone 6 has been released recently ...

  6. Codeforces Round #235 (Div. 2)

    A. Vanya and Cards time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  7. Codeforces Round #493 (Div. 2)D. Roman Digits 第一道打表找规律题目

    D. Roman Digits time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  8. Codeforces Round #532(Div. 2) A.Roman and Browser

    链接:https://codeforces.com/contest/1100/problem/A 题意: 给定n,k. 给定一串由正负1组成的数. 任选b,c = b + i*k(i为任意整数).将c ...

  9. Codeforces Round #235 (Div. 2)C、Team

    #include <iostream> #include <algorithm> using namespace std; int main(){ int n,m; cin & ...

随机推荐

  1. getopt、getopt_long和getopt_long_only

    GNU/Linux的命令行选项有两种类型:短选项和长选项,前者以 '-' 作为前导符,后者以 '--' 作为前导符.比如有一个命令: $ myprog -a vv --add -b --file a. ...

  2. oracle 11gR2 在VM中安装步骤

    oacle的安装 一.在oracle官网可以免费下载oracle的软件和安装文档,如果是在虚拟机中的linux系统里安装,可以用FileZilla Client把软件发送到系统中. linux_11g ...

  3. 基于visual Studio2013解决C语言竞赛题之0806平均分

     题目

  4. 创建用于编译和运行Java程序的批处理文件

    创建用于编译和运行Java程序的批处理文件 每次编译或运行Java程序时,都要在DOS命令行中输入很长的javac或java命令,悟空觉得太麻烦,就编写了一个适用于Windows操作系统的批处理文件b ...

  5. PHP - 使用pear的HTTP_Upload包进行上传

    前台代码: <html> <head> <title>上传文件</title> </head> <body> <form ...

  6. TImage也有OnClick事件,可以当按钮使用,配上合适的图片(背景透明,效果前凸)更是几乎以假乱真

    本质上TImage与TSpeedButton没有什么区别,都是没有句柄的,但都可以执行OnClick事件.有空分析一下.

  7. document.body的一些用法以及js中的常见问题

    document.body的一些用法以及js中的常见问题 网页可见区域宽: document.body.clientWidth; 网页可见区域高: document.body.clientHeight ...

  8. 【linux】linux启动流程

    欢迎转载,转载时请保留作者信息,谢谢. 邮箱:tangzhongp@163.com 博客园地址:http://www.cnblogs.com/embedded-tzp Csdn博客地址:http:// ...

  9. Linux 静态库&动态库调用

    1.什么是库在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.由于windows和linux的本质不同,因此二者库的二进制是不 ...

  10. C++学习之路—继承与派生(一):基本概念与基类成员的访问属性

    (本文根据<c++程序设计>(谭浩强)总结而成,整理者:华科小涛@http://www.cnblogs.com/hust-ghtao,转载请注明) 1   基本思想与概念 在传统的程序设计 ...