D. Roman and Numbers(状压dp)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D. Roman and Numbers(状压dp)相关的知识,希望对你有一定的参考价值。
D. Roman and Numbers(状压dp)
把 n n n的每一位状压,问题等价于选择一个顺序走完这 c n t cnt cnt个位使得 ( m o d m ) = 0 \\pmod{m}=0 (modm)=0答案。
令 d p [ i ] [ j ] dp[i][j] dp[i][j]表示状态 i i i 模 m m m余 j j j的答案。
转移时需要注意最高位对应的数不能为 0 0 0。
初始化: d p [ 0 ] [ 0 ] = 1 dp[0][0]=1 dp[0][0]=1。
而且同一个数字不能在一个状态转移多次,所以可以用一个标记数组,标记哪些数字已经转移过了。
时间复杂度: O ( 10 m × 2 18 ) O(10m\\times 2^{18}) O(10m×218)
// Problem: D. Roman and Numbers
// Contest: Codeforces - Codeforces Round #235 (Div. 2)
// URL: https://codeforces.ml/problemset/problem/401/D
// Memory Limit: 512 MB
// Time Limit: 4000 ms
// Date: 2021-08-11 19:32:34
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e3+5,M=(1<<18)+1,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
ll dp[M][101];
int a[20],cnt,vis[20];
int main(){
ll n;int m;scanf("%lld%d",&n,&m);
while(n) a[++cnt]=n%10,n/=10;
int st=1<<cnt;
dp[0][0]=1;
for(int i=0;i<st;i++){
mst(vis,0);
for(int j=0;j<cnt;j++){
if((1<<j)==i&&!a[j+1]) continue;
if(vis[a[j+1]]||!(i>>j&1)) continue;
vis[a[j+1]]=1;
for(int k=0;k<m;k++)
dp[i][(k*10+a[j+1])%m]+=dp[i^(1<<j)][k];
}
}
printf("%lld\\n",dp[st-1][0]);
return 0;
}
以上是关于D. Roman and Numbers(状压dp)的主要内容,如果未能解决你的问题,请参考以下文章
CF449D Jzzhu and Numbers (状压DP+容斥)
Codeforces 55 D. Beautiful numbers