bzoj1072: [SCOI2007]排列perm

分半搜索,枚举那几个数字分成两半的方案,然后暴力看它们组合Mod d 的余数,并记录,left[i]表示左边的有多少组合mod d = i ,right[i] 也相同,然后用简单数学方法合并

const int N = 15, M = 1010;
int Dat[N], TDat[N], Cnt[2][M], Ans;
int n, Mod;
char S[N];

inline void Solve() ;
inline void NextState(int x, int Pick) ;
inline void Input() {
	int T;
	for(scanf("%d", &T); T--; ) {
		scanf("%s", S), n = strlen(S);
		scanf("%d", &Mod);
		clr(Dat, 0), clr(TDat, 0);
		Rep(i, n) Dat[S[i] - '0']++;
		
		Ans = 0, NextState(0, 0);
		
		printf("%d\n", Ans);
	}
}

inline void NextState(int x, int Pick) {
	if(x >= n >> 1) Solve();
	else {
		For(i, Pick, 9)
			if(TDat[i] < Dat[i]) {
				TDat[i]++;
				NextState(x + 1, i);
				TDat[i]--;
			}
	}
}

inline void Dfs(int Last, int Now, int Type) {
	if(!Last) Cnt[Type][Now % Mod]++;
	else {
		Rep(i, 10)
			if(TDat[i]) {
				TDat[i]--;
				Dfs(Last - 1, Now * 10 + i, Type);
				TDat[i]++;
			}
	}
}
inline void Solve() {
	// Dfs
	clr(Cnt, 0);
	Dfs(n >> 1, 0, 0);
	Rep(i, 10) TDat[i] = Dat[i] - TDat[i];
	Dfs(n - (n >> 1), 0, 1);
	Rep(i, 10) TDat[i] = Dat[i] - TDat[i];
	
	// Count
	int Size = 1;
	Rep(i, n - (n >> 1)) Size *= 10;
	Rep(i, Mod) Ans += Cnt[0][i] * Cnt[1][(Mod - (i * Size) % Mod) % Mod];
}

int main() {
	#ifndef ONLINE_JUDGE
	SETIO("1072");
	#endif
	Input();
	Solve();
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值