CF1875B Jellyfish and Game

文章讲述了在洛谷博客中的一种数列问题,涉及两人轮流交换数字,通过分析奇偶轮次策略,得出最优解:交换对方最大值与自己最小值。通过模拟两次交换过程,确定最终答案。

去洛谷看我的博客

思路

题意大概是两人都有一组数,奇数轮,第一个人可以选择和第二个人交换一个数字也可以不换,偶数轮,第二个人可以选择和第一个人交换一个数字也可以不换。

首先可以猜测,我们每次都应该选择交换对方的最大值和自己的最小值,如果自己的最小值都比对方大的话就不交换。应该比较好想,这里感性证明一下。

如果用的不是自己的最小值去交换,那么总和会变小,对方也不会再交换你的最小值,所以这一步是亏的。

如果交换的不是对方的最大值,如果这个值本身就是你的最大值,那么对方又换回来,没有影响,如果不是,对方交换回去,你就损失了你的最大值,比你交换对方的最大值会亏损一些总和。

如果不需要交换而强制交换,那么会让自己的总和变小,对方再交换一次,又亏损一定的答案,不值得。

那么知道这个性质,我们可以推测,大部分的游戏都一个讨论,两个人把两个数交换过去交换过来,所以我们不需要模拟,可以直接跳过许多无用的游戏。

因为 k k k 的奇偶决定着谁结束游戏,也就是最后是谁交换的,这个信息是很重要的,所以我们可以考虑分成奇偶两种情况分别考虑。

首先,当 k k k 是奇数时,由第一个人结束游戏,所以如果第二个人的最大值比第一个人的最小值还要小的话,第一个人第一轮不交换,后续第二个人交换啥,第一个人就交换回来,所以答案不变。否则的话,第一个人会交换自己的最小值和对方的最大值,然后两人开始互相交换,最后第一个人交换成功,所以答案是原来的总和加上对方的最大值和自己的最小值。

然后,当 k k k 是偶数时,由第二个人结束游戏,和上面一种情况比较相似,如果第二个人的最大值比第一个人的最小值还要小,那么第一轮,第一个人不会交换,那么后续第二个人就可以成功交换,所以答案是总和减去第一个人的最大值加上第二个人的最小值。否则,答案不变。

想清楚了后,发现很简单,只需要在输入的时候记录两个人的最大最小值即可。

快速地写完,发现 WA 了。

思考了一下,发现当对方的最大值交换过来不是自己的的最大值时,就不是互相交换两个数,答案的变化也没有这么简单。

所以我们可以考虑先计算交换两轮的结果,第一轮可以保证最大值在第一个人身上,第二轮可以保证最大值在第二个人身上,并且最小值在第一个人身上,这样每次都必定交换最小值和最大值。

证明比较简单,第一轮如果最大值在自己身上,无论交不交换,最大值都还是自己的,如果不在自己身上,则必然交换,最大值就是第一个人的了。第二轮,第二个人必定交换,最大值就跑到第二个人身上了,第二个人会把自己的最小值给第一个人,所以第一个人同时有了自己和第二个人的最小值,所以最小值一定在第一个人身上。

所以我们可以先模拟两次过程,再上面的结论即可。

AC code

#include<bits/stdc++.h>
using namespace std;
long long T,n,m,k,sum1,sum2,minn,maxn,t,mi,ma;
multiset<long long>sa,sb;
int main()
{
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld%lld%lld",&n,&m,&k),sum1=sum2=0,sa.clear(),sb.clear();
		for(int i=1;i<=n;++i) scanf("%lld",&t),sum1+=t,sa.insert(t);//分别用set存下来
		for(int i=1;i<=m;++i) scanf("%lld",&t),sum2+=t,sb.insert(t);
		for(int i=1;i<=2&&i<=k;++i)//模拟2次,注意k<=2的情况
		{
			if(i%2)
			{
				auto a=sa.begin(),b=sb.end();--b;
				if(*b-*a>0) sum1+=*b-*a,sum2+=*a-*b,sa.insert(*b),sb.insert(*a),sa.erase(a),sb.erase(b);
			}
			else
			{
				auto a=sa.end(),b=sb.begin();--a;
				if(*a-*b>0) sum1+=*b-*a,sum2+=*a-*b,sa.insert(*b),sb.insert(*a),sa.erase(a),sb.erase(b);
			}
		}
		k-=2;
		auto mina=sa.begin(),maxa=sa.end(),minb=sb.begin(),maxb=sb.end();--maxa,--maxb;//用set直接找到双方的最大最小
		if(k<=0) printf("%lld\n",sum1);
		else if(k%2) printf("%lld\n",sum1+max(*maxb-*mina,0ll));
		else printf("%lld\n",(*maxb<*mina)?sum1-max(*maxa-*minb,0ll):sum1);//上面的结论
	}
	return 0;
}
### Jellyfish 工具的使用教程 Jellyfish 是一款用于高效计数 k-mers 的生物信息学工具,广泛应用于基因组数据分析。以下是关于其使用的详细说明: #### 安装过程 为了正确安装 Jellyfish,可以按照以下方式操作[^2]: ```bash wget -c https://github.com/gmarcais/Jellyfish/releases/download/v2.3.1/jellyfish-2.3.1.tar.gz tar -zxvf jellyfish-2.3.1.tar.gz mkdir jellyfishlocation cd jellyfish-2.3.1 ./configure --prefix=/jellyfishlocation make -j 4 make install ``` 完成上述步骤后,Jellyfish 将被成功安装到指定路径 `/jellyfishlocation`。 #### 基本概念 Jellyfish 主要功能是对 DNA 序列中的 k-mers 进行统计分析。k-mer 表示长度为 `k` 的连续子序列,在基因组研究中具有重要意义[^1]。 #### 使用方法 Jellyfish 提供了一系列命令行选项来执行不同的任务。常见的用法如下所示: 1. **构建 k-mer 统计表** 构建输入 FASTA 文件的 k-mer 频率表。 ```bash jellyfish count -m 21 -s 100M -t 8 input.fasta -o output.jf ``` 参数解释: - `-m`: 设置 k-mer 的大小 (此处为 21)。 - `-s`: 指定哈希表的最大内存占用量 (单位为字节, 此处为 100MB)。 - `-t`: 并行线程数量 (此处为 8)。 - `-o`: 输出文件名。 2. **查询 k-mer 频率** 查询特定 k-mer 出现的频率。 ```bash jellyfish query output.jf ACGTACGTACGTACGTACGT ``` 3. **导出 k-mer 列表** 导出完整的 k-mer 和对应的频次列表。 ```bash jellyfish dump -c -t output.jf > kmers.txt ``` 参数解释: - `-c`: 包含计数值。 - `-t`: 输出纯文本格式。 #### Python 库支持 除了作为独立工具外,还存在名为 `jellyfish` 的 Python 库,主要用于字符串匹配和模糊比较[^3]。该库的功能与生物信息学无关,而是专注于自然语言处理领域中的相似度计算。例如: ```python import jellyfish print(jellyfish.levenshtein_distance('hello', 'hallo')) # 计算编辑距离 print(jellyfish.soundex('Smith')) # 获取音码表示 ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值