首页 > 其他分享 >CF1969F-Card Pairing【dp】

CF1969F-Card Pairing【dp】

时间:2024-08-10 17:54:14浏览次数:13  
标签:两张牌 int Pairing leq dp 类型 include Card CF1969F

正题

题目链接:https://www.luogu.com.cn/problem/CF1969F


题目大意

有一个长度为 \(n\) 的卡牌序列 \(a\) ,每张牌是 \(1\sim k\) 中的一个类型,你先取出序列里的前 \(k\) 张牌,然后你每次可以选择两张牌打出然后再抽两张牌,如果类型一样就加一分。

求打完所有牌你最多能加多少分。

\(2\leq k\leq n\leq 1000\)


解题思路

考虑到手牌数量和类型数量是一样的,所以我们如果类型没有一样花色的牌那么手上肯定是所有类型的牌都一样,所以此时我们可以确定手牌情况。

设 \(f_i\) 表示在抽取完第 \(i\) 张牌后我们如果手上没有类型相同的牌,我们前面最多能拿多少分。

那么此时我们就可以对于每个 \(f_i\) 暴力往后枚举转移,此时我们需要先丢掉两张牌,我们可以先不确定这两张牌,到后面再丢。

当我们走到一个位置我们手上只有两个牌的出现次数是偶数次,那么如果我们之前丢掉这两张牌就会进入到一个新的手上所有牌类型都不同的状态,此时就可以进行一次转移。

转移到终点时需要根据前面的转移状态统计答案时有不少细节可以看代码。

时间复杂度:\(O(n^2)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
using namespace std;
const int N=1100;
int n,k,a[N],v[N],f[N],c[N],answer;
set<int> z;
map<int,bool> mp;
map<int,bool>::iterator it;
void dfs(int x){
	for(int i=1;i<=k;i++)v[i]=1,c[i]=0;
	z.clear();mp.clear();
	int ans=f[x],ban=0,div=k;
	answer=max(answer,ans);
	for(int i=x+1;i<=n;i++){
		if(v[a[i]])ans++,v[a[i]]=0,div--,z.insert(a[i]);
		else v[a[i]]=1,div++,z.erase(a[i]);
		if(div==k-2){
			int x=*z.begin(),y=*z.rbegin();
			if(!mp[x*k+y-1]){
				mp[x*k+y-1]=1,ban++;
				f[i]=max(f[i],ans-2);
				if(ban==k*(k-1)/2)break;
			}
		}
		if(i==n){
			it=mp.begin();
			while(it!=mp.end()){
				int y=((*it).first)%k+1,x=((*it).first)/k;
				if(v[y]&&v[x])c[x]++,c[y]++;
				it++;
			}
			answer=max(answer,ans-2);
			for(int i=1;i<=k;i++)
				if(v[i]){
					if(c[i]<div-1){
						answer=max(answer,ans);
						break;
					}
				}
		}
	}
	return;
}
int main()
{
	memset(f,0xcf,sizeof(f));
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	int div=0;
	for(int i=1;i<=n;i++){
		if(v[a[i]])answer++,v[a[i]]=0,div--;
		else v[a[i]]=1,div++;
		if(div==k){
			f[i]=answer;
			break;
		}
	}
	for(int i=1;i<=n;i++)
		if(f[i]>=0)dfs(i);
	printf("%d\n",answer);
	return 0;
}

标签:两张牌,int,Pairing,leq,dp,类型,include,Card,CF1969F
From: https://www.cnblogs.com/QuantAsk/p/18352586

相关文章

  • LeetCode | 20 ValidParentheses
    分析括号成对出现,键值对类型括号字符序列嵌套出现,不能错位,顺序具有对称性为什么不用数组这种数据结构来记录数量?因为这种方法不能保证括号的正确顺序。例如,字符串'({[)}]'会被认为是有效的。栈解决有效括号问题当遇到一个左括号时,我们需要记住它,以便在后续遇到相应的右括......
  • dpwwn-01靶机笔记
    dpwwn-01靶机笔记概述这是一台Vulnhub的靶机,主要在web方面,我们无法找到突破口时,应该怎样抉择mysql和ssh的爆破,以及弱口令的尝试。我这里准备了连接,当然你也可去Vulnhub平台自己下载dpwwn-01靶机:https://pan.baidu.com/s/1P5Peude95xYcsUsKd0_55w?pwd=8v4h提取码:8v4h一、nmap......
  • lg-dp3
    lg-dp3计数的东西有什么特点、转化/好的刻画方式AFarthestCity题面关键信息:权值为1的最短路---bfs---分层那么显然加一个点他只能与上一层连,和一层内部连。则设\(f_{i,j}\)为[点数,最后一层点数]有\[f_{i,j}=2^{j\choose2}\sum_{k=1}^{i-j}{f_{i-j,k}(2^k-1)^j{n......
  • UDP/TCP网络调试助手 NetAssist【调试工具】下载
    链接:https://pan.baidu.com/s/1QgL4XZdKNW39nFe18feBbw?pwd=1122提取码:1122–来自百度网盘超级会员V3的分享接收设置ASCII:以ASCII格式显示接收到的数据。ASCII是一种字符编码标准,用于表示文本数据。HEX:以十六进制格式显示接收到的数据。十六进制显示更适合查看和调试......
  • 宝塔面板安装后wordpress优化教程
    宝塔面板安装wordpress之后,一直有一个头痛的问题按F5会导致cpu和内存100%,这个问题也困扰了我一个月,后面也是各种解决方案都不太理想!现在我出来一个教程,按我的思路我的服务器是2H2G的阿里云服务器!里面只有一个wordpress站点,也就是现在你所看到的站点运行环境:nginx1.......
  • 做题小结 dp训练4
    第一个我按dp找结果是个二分我还想半天这怎么dp不过这题目也很有意义首先我一直以为vector的low或者upp下标只能用distance求现在看来是错的不要再写auto迭代器写法用int就行减初始指针就行然后二分的话思路也很好先存进去然后在跑t的时候先开一个指针然后对于......
  • 做题小结 dp训练3
    第一个这道题主要思考到一个不可以连续两步以及最大往左移动5位就像背包一样所以我们开个二维的dp数组表示 for(intj=1;j<=z;j++){ if(i+j*2<=k+1&&i-1>=1){ dp[i][j]=max(dp[i][j-1]+a[i-1]+a[i],max(dp[i][j],dp[i-1][j]+a[i])); ......
  • dp套dp
    我们先说一下\(dp\)套\(dp\)大概是个什么东西。感性理解一些,你现在有一个动态规划数组\(g\),然后你的\(f\)用\(g\)的某种方式作为下标进行转移。事实上,这个\(g\)需要满足单调性,然后相当于你是在一个\(DAG\)上做\(dp\)。为什么要满足单调性,否则有可能出现环,有环代表......
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-08 仿真验证
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 4仿真验证仿真代码的顶层如下......
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-09 ICMP层程序设计
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 5上板调试5.1硬件连接本次......