BZOJ1072: [SCOI2007]排列perm(状压DP)

题意
对于一个给定的字符串s,问有多少种排列所构成的数字可以被d整除.
解法

我们可以直接爆搜,但是复杂度极高,因为爆搜过程中我们有大量重复过程,因此可以定义一个数组保存状态,dp[s][i] 代表将s的对应的二进制为1对应的数选中后余数为i的状态,例如100101代表已经选中了第1,3,6这三个数;

code
#include <bits/stdc++.h>
using namespace std;
 
char s[21];
int d;
bool vis[21];
int dp[1<<12][1000];
int l;
 
int dfs(int j, int k, int ss) {
    if(dp[ss][k] != -1) {
        return dp[ss][k];
    }
    if(j == l) {
        if(k==0) {
            return 1;
        }
        return 0;
    }
    dp[ss][k] = 0;
    for(int i = 0; i < l; ++ i) {
        if(i>0 && s[i-1]==s[i] && !vis[i-1]) continue;      //因为s种可能出现相同的数,因此为了防止重复我们可以在新的序列中不改变重复的数在原序列中的相对位置
        if(!vis[i]) {
            vis[i] = true;
            dp[ss][k] += dfs(j+1, (k*10+s[i]-'0')%d, ss|(1<<i));
            vis[i] = false;
        }
    }
    return dp[ss][k];
}
 
int main() {
    int t;
    scanf("%d", &t);
    while(t --) {
        scanf("%s%d", s, &d);
        l = strlen(s);
        sort(s, s+l);
        memset(vis, 0, sizeof(vis));
        memset(dp, -1, sizeof(dp));
        printf("%d\n", dfs(0, 0, 0));
    }
    return 0;
}

转载于:https://www.cnblogs.com/topk/p/7426697.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值