lightoj-1021 - Painful Bases(状压+数位dp)

1021 - Painful Bases
PDF (English) Statistics Forum
Time Limit: 2 second(s) Memory Limit: 32 MB
As you know that sometimes base conversion is a painful task. But still there are interesting facts in bases.

For convenience let‘s assume that we are dealing with the bases from 2 to 16. The valid symbols are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E and F. And you can assume that all the numbers given in this problem are valid. For example 67AB is not a valid number of base 11, since the allowed digits for base 11 are 0 to A.

Now in this problem you are given a base, an integer K and a valid number in the base which contains distinct digits. You have to find the number of permutations of the given number which are divisible by K. K is given in decimal.

For this problem, you can assume that numbers with leading zeroes are allowed. So, 096 is a valid integer.

Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a blank line. After that there will be two integers, base (2 ≤ base ≤ 16) and K (1 ≤ K ≤ 20). The next line contains a valid integer in that base which contains distinct digits, that means in that number no digit occurs more than once.

Output
For each case, print the case number and the desired result.

Sample Input
Output for Sample Input
3

2 2
10

10 2
5681

16 1
ABCDEF0123456789
Case 1: 1
Case 2: 12
Case 3: 20922789888000

解题思路:  状压dp+数位dp

dp[i][j] , i 的二进制上为1的表示这个把对应位置的数取了,这种方法相对于暴力全排列来说,他可以同时取多个数,所以可以节省很多时间。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long ll;

ll dp[1<<17][25];

int main(){

    int T,n,limit,k,len,num[20];
    char str[20];

    scanf("%d",&T);
    for(int t=1;t<=T;t++){
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&n,&k);
        scanf("%s",str);

        len = strlen(str);
        for(int i=0;i<len;i++){  // 转化成正常数字
            if(str[i]<=‘9‘&&str[i]>=‘0‘) num[i] = str[i] - ‘0‘;
            else num[i] = str[i]-‘A‘+10;
        }
        dp[0][0] = 1;
        limit = (1<<len)-1;
        for(int i=0;i<=limit;i++) //决定当前所选的数 例如0001 就相当于选了个位的数
            for(int kk = 0;kk<k;kk++) //枚举当前可能出现的余数情况。
                if(dp[i][kk])            // 如果dp[i][kk] = 0,加了也没什么用,所以剪枝
                    for(int j=0;j<len;j++) // 枚举可以添加进去的数
                        if(!(i&(1<<j)))        //如果i&(1<<j)!=0  就表明j所选的数,i里面已经存在了,所以不符合全排列情况
                        dp[i|(1<<j)][(kk*n+num[j])%k] += dp[i][kk];    // 将先前的情况添加到后续情况 kk是num[j]前面的数 所以要*n; 

        printf("Case %d: %lld\n",t,dp[limit][0]);

    }

    return 0;
} 
时间: 2024-10-08 21:38:28

lightoj-1021 - Painful Bases(状压+数位dp)的相关文章

SPOJ BALNUM Balanced Numbers 状压+数位DP

一开始想了一个用二进制状压的方法,发现空间需要的太大,光光memset都要超时 = = 其实不用每次都memset 也可以用三进制,一开始直接打表出所有的状态转移就好 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream&g

lightoj 1021 - Painful Bases(数位dp+状压)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1021 题解:简单的数位dp由于总共就只有16个存储一下状态就行了. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; ll dp[1 << 17

Topcoder SRM655 DIV2 950 NineEasy 状压 + 数位 dp

题意:要你构造一个n位的数子 ,给你m(1-5)个询问,每一次询问取一些位数的数组成一个新数且这个数 %9 ==  0 , 问你要满足这m个询问的数字有多少个(允许前缀0). 解题思路:把每一种情况状压,得到一个最多  9x9x9x9x9 的情况,然后根据 每个数的询问决定状态转移方程. 解题代码: 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "NineEasy.cpp" 7 #include <cstd

UVA 11600 Masud Rana 并查集+状压概率dp

题目链接:点击打开链接 题意:给定一个无向图,给定的边是已经存在的边,每天会任选两个点新建一条边(建过的边还会重建) 问:使得图连通的天数的期望. 思路:状压喽,看别人都是这么写的,n=30,m=0 我也不知道怎么办了.. 当前连通块点数为X 加入一个Y个点的连通块需要的天数为 Y/(n-X); Masud Rana, A Daring Spy Of Bangladesh Counter Intelligence. He is in a new mission. There is a total

codeforces 482c 状压+概率DP

题意:给出N个不同的串,长度一样,别人随机选一个串,你要询问他那个串某一个位置是什么字符直到能确定那个串才能停止,问询问次数的期望. 题解:50个串20个位置容易想到状压,把字符串长度状压先考虑能否在某一个状态确定哪些字符串能确定哪些不能确定,需要2^m*m次,然后时间上不能再乘以n不然会爆,想想只要我知道到达某一个猜位置状态的概率dp[i],再知道相对应有哪些字符串可以确定和不可以确定,用f[i]来表示,那么对于不能确定的字符串相当于就要再猜一步,那么加上这个状态的概率就行了,不会再需要乘以n

HDU 4336 Card Collector(状压 + 概率DP 期望)题解

题意:每包干脆面可能开出卡或者什么都没有,一共n种卡,每种卡每包爆率pi,问收齐n种卡的期望 思路:期望求解公式为:$E(x) = \sum_{i=1}^{k}pi * xi + (1 - \sum_{i = 1}^{k}pi) * [1 + E(x)]$,即能转换到x情况的期望+x情况原地踏步的期望. 因为n比较小,我们可以直接状压来表示dp[x]为x状态时集齐的期望.那么显然dp[111111111] = 0.然后我们状态反向求解.最终答案为dp[0]. 然后来看期望的求解:$E(x) =

Light oj 1021 - Painful Bases

题意:  给一个B进制的数,一个10进制的数K,B进制数有x位, 对着x位进行全排列的话,有x!种可能, 问这x!的可能中,有多少种可以整除K,各个位置上的数字都不同. 思路:状态压缩,数位DP #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<vector> #include<set&

CF16E Fish(状压+期望dp)

[传送门[(https://www.luogu.org/problemnew/show/CF16E) 解题思路 比较简单的状压+期望.设\(f[S]\)表示\(S\)这个状态的期望,转移时挑两条活着的鱼打架.时间复杂度\(O(2^n*n^2)\). 代码 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using n

LightOJ1021---Painful Bases (状压dp)

As you know that sometimes base conversion is a painful task. But still there are interesting facts in bases. For convenience let's assume that we are dealing with the bases from 2 to 16. The valid symbols are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D