CF Round 235 D 状态压缩 dp

35 篇文章 0 订阅

这是一个状态压缩 dp

我发现,状态压缩dp难点就在于怎么设计状态的转换。

这道题当时没有做出了来,眼睁睁的看着一道 dp 没过去。。。次奥。

毕竟取摸这个运算,是没有后效性的,前面不管你是怎么搞的数,只要摸是一样的,再加上一个数的模我就可以唯一的确定。

这样dp就有了根据。

dp 的状态怎么想,毕竟只有 18 个数字,每个数字选不选,有(1<<18)种状态,那我就从第一个位置开始选数字,以后每选一个数字就加到已经选择的数字的末尾。

那好 dp[1<<18][100] 就可以来表示状态了,问题是,怎么转移?

首先,真正的转移方式应该是从 1 的个数少的状态向1的个数多的状态进行转移。

那这样该怎么写啊?

当然,你可以使用dfs,不管他怎么转移,有需要转移的地方我就dfs,但是这个问题,明显不好从后面往前推。只能从前面往后推。

dfs是有局限的。

想起来wata对于旅行商问题的解释。如果 集合 A 包含 集合 B , 则状态 A > 状态 B。这个问题可以直接从1开始增加

#include <stdio.h>
#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>

using namespace std;

typedef long long ll;
#define MS(x,d) memset(x,d,sizeof(x))
ll dp[1<<18][101]={0};
char num[500];
int cnt[50];
int m;
ll fac[20];
int main()
{
    while(scanf("%s%d",num,&m)!=EOF)
    {
        MS(dp,0);
        MS(cnt,0);
        int len=strlen(num);

        for(int i=0;i<len;i++)
            cnt[num[i]-='0']++;
        fac[0]=1;
        for(ll i=1;i<=19;i++)
            fac[i]=i*fac[i-1];
        ll d=1;
        for(int i=0;i<10;i++)
            d*=fac[cnt[i]];
        dp[0][0]=1;
        for(int i=0;i<(1<<len);i++)
        {
            for(int j=0;j<len;j++)
            {
                if( (!(i & (1<<j)) )&&(i||num[j]))
                {
                    for(int k=0;k<m;k++)
                        dp[i|(1<<j)][(k*10+num[j])%m]+=dp[i][k];
                }
            }
        }
        cout<<(dp[(1<<len)-1][0]/d)<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值