[CF 743E] Vladik and cards

7 篇文章 0 订阅

题目

戳这洛谷

思路

似乎想到一个状态,感觉不甚靠谱。

正解:

似乎和我的思考有一些相似之处,然而我是把出现次数放进 d p dp dp 数组的状态里,这样是不好搞的,这就是我放弃自己思路的原因。

而题解里选择的方法是:直接二分这个最少的出现次数——似乎很可行?

定义 d p [ i ] [ j ] dp[i][j] dp[i][j] :考虑前 i i i 位,状态(即为数组出现的不可重集)为 j j j 可得到的最长序列长度。满足二分出来的最小长度 x x x。转移似乎很简单了,考虑 x x x 个和 x + 1 x + 1 x+1 个就好了。

Code

LL n, a[MAXN], dp[MAXN][MAXM], Cnt, Cur[MAXK];
// dp[i][j] : 到第 i 位,出现集合为 j 的最大长度
vector<LL> Pos[MAXK];
inline LL Check(LL x)
{
	memset(Cur, 0, sizeof Cur);
	memset(dp, -1, sizeof dp);
	dp[1][0] = 0;
	for (Int i = 1; i <= n; ++ i)
	{
		for (Int j = 0; j < (1 << 8); ++ j)
		{
			if (dp[i][j] == -1)
				continue;
			for (Int k = 1; k <= 8; ++ k)
			{
				if (j & (1 << (k - 1)))
					continue;
				LL To = Cur[k] + x - 1; // Cur : 第几个 k 
				if (To >= (int) Pos[k].size())
					continue;
				dp[Pos[k][To]][j | (1 << (k - 1))] = Max(dp[Pos[k][To]][j | (1 << (k - 1))], dp[i][j]);
				if (To + 1 >= (int) Pos[k].size())
					continue;
				To ++;
				dp[Pos[k][To]][j | (1 << (k - 1))] = Max(dp[Pos[k][To]][j | (1 << (k - 1))], dp[i][j] + 1);
			}
		}
		Cur[a[i]] ++;
	}
	LL Res = -1;
	for (Int i = 1; i <= n; ++ i)
		Res = Max(Res, dp[i][(1 << 8) - 1]);
	if (Res == -1)
		return -1;
	return Res * (x + 1) + (8 - Res) * x;
}
LL Ans;
int main()
{
	read( n );
	for (Int i = 1; i <= n; ++ i)
	{
		read( a[i] );
		Pos[a[i]].push_back( i );
	}
	LL l = 1, r = 1000;
	while (l + 1 < r)
	{
		// printf("%lld %lld\n", l, r);
		LL Mid = (l + r) / 2;
		LL Get = Check( Mid );
		if (Get != -1)
			Ans = Get, l = Mid;
		else r = Mid - 1;
	}
	Ans = Max(Check( l ), Check( r ));
	if (Ans == -1)
	{
		Ans = 0;
		for (Int i = 1; i <= 8; ++ i)
			if ( Pos[i].size() )
				Ans ++;
	}
	printf("%lld", Ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值