[Codefoces 401D]Roman and Numbers 数位dp

http://codeforces.com/problemset/problem/401/D

题目大意:给定一个数字n,将n的每一位数字重新排列,求在这些排列数之中可以被n整除的方法数。

解题思路:

暴力超时……

大多数人的写法是进行位压缩,不过那样的话需要2^18*100 的空间,效率比较低,重复状态数较多,处理起来也不方便,这一题是给出了512M的空间。但是如果空间再小一倍,前者的方法就无能为力了。

发现有一种对于数位dp来说比较好的状态压缩方式,直接根据数码x出现的次数进行状态压缩。比如说333444,如果用前者的方法压缩就需要2^6=64的空间,而直接按照出现次数压缩就只需要3*3的空间,对于极限数据,利用均值不等式,也差不多只需(ceil(18/10+1)^10)=59049的空间,提高了空间的利用率(原来是2^18=262144)与判重的效率。

dp方程也很容易建立对于编码i所有对n取余得j的数字 其余数乘10加上下一位数字得到下一种状态的一部分。结果就是全部数字都使用的余为0的情况(dp[s][n])。

这种压缩的关键在于codeit和decode函数

code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#define SIZES 40000
using namespace std;
char n[20];
int c[10],d[10],tim[10],m;
long long dp[60000][100];
int len;
int codeit(int *te)
{
    int res=0;
    for (int i=0;i<10;i++)
        res=res*(tim[i]+1)+te[i];
    return res;
}
long long decode(int l,int *t)
{
    for (int i=9;i>=0;i--){
        t[i]=(l%(tim[i]+1));
        l/=(tim[i]+1);
        }
}
int main()
{
    int s;
    while(~scanf("%s%I64d",n,&m)){
    memset(dp,0,sizeof dp);
    len=strlen(n);
    memset(tim,0,sizeof(tim));
    for (int i=0;i<len;i++)
        ++tim[n[i]-'0'];
    int s=codeit(tim);
//    printf("%d\n",s);
    dp[0][0]=1;
    for (int i=0;i<s;i++){
        int t[10];
        decode(i,t);
        for (int j=0;j<10;j++)
            if (i+j)
            if (tim[j]-t[j]){
            t[j]++;
            int pt=codeit(t);
            for (int k=0;k<m;k++)
            dp[pt][(k*10+j)%m]+=dp[i][k];
            t[j]--;
            }
        }
    printf("%I64d\n",dp[s][0]);
    }
}

[Codefoces 401D]Roman and Numbers 数位dp,布布扣,bubuko.com

时间: 2025-01-31 09:21:33

[Codefoces 401D]Roman and Numbers 数位dp的相关文章

Codeforce 401D Roman and Numbers[数位DP+状态压缩]

给出数n和m,求n的所有排列中,模m得0的有多少个 n (1?≤?n?<?1018) and m (1?≤?m?≤?100). 暴力法我们直接枚举n的所有排列,显然18!超时. 考虑怎么dp 假设给了我们数n=23765 显然有 (237%m*10+6)%m=2376%m (367%m*10+2)%m=3672 我们很自然的想到了 这样的状态转移 dp[i][k] i代表取的数的状态 代表在取数状态为i的情况下模m为k的数有多少 比如 对于23765的356 取数状态为01011 dp方程就是

cf55dBeautiful numbers数位dp

想到 最小公倍数 其余的就好搞了 ,可是没想到 #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <

Balanced Numbers数位dp

三进制搞下, 0  表示没出现过,  第i位为1 表示 i出现了奇数次,  2表示i 出现了偶数次. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #includ

uva 10712 - Count the Numbers(数位dp)

题目链接:uva 10712 - Count the Numbers 题目大意:给出n,a,b:问说在a到b之间有多少个n. 解题思路:数位dp,dp[i][j][x][y]表示第i位为j的时候,x是否前面是相等的,y是否已经出现过n.对于n=0的情况要特殊处理前导0,写的非常乱,搓死. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using na

poj 3340 Barbara Bennett&#39;s Wild Numbers(数位DP)

Barbara Bennett's Wild Numbers Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3153   Accepted: 1143 Description A wild number is a string containing digits and question marks (like 36?1?8). A number X matches a wild number W if they hav

CodeForces 55D Beautiful numbers 数位DP+数学

题意大概是,判断一个正整数区间内有多少个整数能被它自身的每一个非零的数字整除. 因为每一个位置上的整数集s = {0,1,2,3,4,5,6,7,8,9} lcm(s) = 2520 现在有一个整数t是由s中一个或者多个数字构成的,记为abcde,显然t = a*10^4+b*10^3+c*10^2+d*10^1+e 要使得t能被a,b,c,d,e整除,必然有t % lcm(a,b,c,d,e) = 0 因为a,b,c,d,e去重之后一定是s的一个子集,所以lcm(s)一定是lcm(a,b,c,

HDU 4722 Good Numbers (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4722 思路:数位dp,dp[i][j]表示到第i位,数字和%10为j,然后进行dp,注意完全匹配的情况是要+1,而其他情况是从0 到 9 都要考虑 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; int

Codeforces Beta Round #51---D. Beautiful numbers(数位dp, 巧妙)

Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with this and just count the quantity of beautiful num

CodeForces 55D Beautiful numbers(数位dp&amp;&amp;离散化)

题目链接:[kuangbin带你飞]专题十五 数位DP A - Beautiful numbers 题意 ps:第一道数位dp,题真好,虽然是参考大牛方法悟过才a,但仍收获不少. 求一个区间内的Beautiful numbers有多少个.Beautiful numbers指:一个数能整除所有组成它的非0数字. 例如15可以被1和5整除,所以15是Beautiful numbers. 思路 Beautiful numbers指:一个数能整除所有组成它的非0数字. 等同于 一个数能整除 所有组成它的