lightoj 1021 从当前转移到其他状态的状压dp

本文介绍了一个关于基数转换的问题,需要找出特定基数下含有不同数字的有效整数中,可以被给定整数K整除的所有排列组合的数量。文章详细解释了如何使用动态规划解决这一问题,并提供了一个C++实现的代码示例。

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

这个题真是很迷…
看别人的博客才学会的…..
特别是这个状态转移方程我自己想不出来….
通过往括号里加了一项%kk才成立的…
感觉还需要多看几遍….作为dp这个题没啥难点…
是从自己有状态转移到其他没有状态的地方扩展起来这样的….
应该深刻理解….

补充:已经学会了
那个状态转移方程推出来的也不难,之所以只用乘一次base是因为每次转移之前都乘了base所以没有遗漏..
之前就是这里不理解…..
突然就懂了….

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<memory.h>
using namespace std;
long long  dp[1<<16][20];
int jinzhi[200];
int tu[21];
int main()
{
    for(int a='0';a<='9';a++)jinzhi[a]=a-'0';
    for(int a='A';a<='Z';a++)jinzhi[a]=a-'A'+10;
    int T;
    cin>>T;
    int u=0;
    string q;
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        int bas,kk;
        scanf("%d%d",&bas,&kk);
        cin>>q;
        memset(tu,0,sizeof(tu));
        int len=q.size();
        for(int a=0;a<len;a++)tu[a+1]=jinzhi[q[a]];
        int zong=1<<len;
        dp[0][0]=1;
        for(int a=0;a<zong;a++)
        {
            for(int b=0;b<kk;b++)
            {
                if(dp[a][b])
                {
                    for(int c=0;c<len;c++)
                    {
                        if(a&(1<<c))continue;
                        dp[a|(1<<c)][(b*bas+tu[c+1]%kk)%kk]+=dp[a][b];
                    }
                }
            }
        }
        printf("Case %d: %lld\n",++u,dp[zong-1][0]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值