ICPC-2021-台北 Largest Remainder

ICPC-2021-台北 Largest Remainder

题目描述

给定 D D D 个大小为 1 1 1 ~ 9 9 9 的数字 d d d,用这些数字拼成一个数,要求该数模 K K K 值最大。模数相同则输出拼成的数最大的一个。

数据范围

1 ≤ D ≤ 16 , 1 ≤ d ≤ 9 , 1 ≤ K ≤ 200 1 \leq D \leq 16, 1 \leq d \leq 9, 1 \leq K \leq 200 1D16,1d9,1K200


题解报告

状压 D P DP DP,令 d p [ s ] [ j ] dp[s][j] dp[s][j] 表示,在状态集合为 s s s 的情况下,余数为 j j j 的最大数。

s s s 二进制表示下,若第 i i i 位为 1 1 1,表示该状态集合中包含 d [ i ] d[i] d[i],否则不包含。

状态为 s s s 时,枚举每个数字 d [ i ] d[i] d[i],若 i i i 不在当前集合 s s s 中,

则将 i i i 加入 s s s 集合中,同时枚举余数 j j j

因为要求数最大,所以转移时 i i i 自动加入到最后一位,

状态 d p [ s ] [ j ] dp[s][j] dp[s][j] 就可以转移到状态 d p [ s ∣ ( 1 < < i ) ] [ ( j ∗ 10 + d [ i ] ) % K ] dp[s | (1 << i)][(j * 10 + d[i]) \% K] dp[s(1<<i)][(j10+d[i])%K]

也即 d p [ s ∣ ( 1 < < i ) ] [ n x t ] = m a x ( d p [ s ∣ ( 1 < < i ) ] [ n x t ] , d p [ s ] [ j ] ∗ 10 + d [ i ] ) dp[s | (1 << i)][nxt] = max (dp[s | (1 << i)][nxt], dp[s][j] * 10 + d[i]) dp[s(1<<i)][nxt]=max(dp[s(1<<i)][nxt],dp[s][j]10+d[i])

式中 n x t = ( j ∗ 10 + d [ i ] ) % K nxt = (j * 10 + d[i]) \% K nxt=(j10+d[i])%K

时间复杂度 O ( 2 D ⋅ D ⋅ K ) O(2^{D} \cdot D \cdot K) O(2DDK),略极限。

AC代码:

#include <bits/stdc++.h>
#define ll long long
#define int ll
using namespace std;
const int maxn = 2e2 + 5;

int D, K;
int d[25];
int dp[1 << 16][maxn];

void init () {}

void charming () {
	cin >> D >> K;
	for (int i = 0; i < D; ++i) cin >> d[i];	
	memset (dp, -1, sizeof dp);
	dp[0][0] = 0;
	for (int s = 0; s < (1 << D); ++s) {
		for (int i = 0; i < D; ++i) {
			if ((s >> i) & 1) continue;
			for (int j = 0, nxt; j < K; ++j) {
				if (dp[s][j] == -1) continue;
				nxt = (j * 10 + d[i]) % K;
				dp[s | (1 << i)][nxt] = max (dp[s | (1 << i)][nxt],
				dp[s][j] * 10 + d[i]);
			}
		}
	}
	for (int i = K - 1; i >= 0; --i) {
		if (dp[(1 << D) - 1][i] != -1) {
			cout << dp[(1 << D) - 1][i] << endl;
			break;
		}
	}
}

signed main () {
	charming ();
	return 0;	
}

收获&总结

状压 D P DP DP 压缩的状态常常是某个元素是否存在,转移的过程常常是不断将未在当前元素加入到当前元素的过程。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值