2018.10.23【SCOI2007】【BZOJ1072】【洛谷P4163】排列(状压DP)

BZOJ传送门

洛谷传送门


解析:

水题状压。显然我们可以枚举状态 f s t a , k f_{sta,k} fsta,k表示当前选择了 s t a sta sta中的数, % d \%d %d的结果是 k k k的方案数。

考虑怎么避免重复,首先用排列去重是可以的,但是这明明是一道水题,有什么必要去推式子呢?

我们直接预处理出选择每一个数的前提状态,其实就是当序列中有多个 i i i的时候,保证选择第二个 i i i的时候第一个 i i i已经出现在状态里面了。

随便乱搞一发就能过。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

char s[10];
ll f[1<<11][1005];
int cnt[10];
int pre[10];
int d,len;
int T;
signed main(){
	T=getint();
	while(T--){
		scanf("%s",s);
		d=getint();len=strlen(s);
		memset(f,0,sizeof f);
		memset(cnt,0,sizeof cnt);
		for(int re i=0;i<len;++i)s[i]^=48,++cnt[s[i]];
		sort(s,s+len);
		for(int re i=0;i<len;++i){
			--cnt[s[i]];
			if(cnt[s[i]])pre[i]=1<<(i+1);
			else pre[i]=0;
		}
		f[0][0]=1;
		for(int re i=0;i<(1<<len);++i){
			for(int re j=0;j<len;++j){
				if(((i&pre[j])==pre[j])&&!(i&(1<<j))){
					for(int re k=0;k<d;++k)f[i|(1<<j)][(k*10+s[j])%d]+=f[i][k];
				}
			}
		}
		cout<<f[(1<<len)-1][0]<<"\n";
	}
	return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值