Codeforces Round #716 (Div. 2) CD题解证明

本文解析了CF4.19的C、D两题。C题通过证明找到满足子序列乘积模n为1的最长序列。D题则讨论了如何划分子序列使得每个子序列中出现最多的元素数量不超过子序列长度的一半。

4.19CF题解;
关于CD的证明:

C:

本题求的是一个1到n-1的序列,请找出一个最长的满足要求的子序列,求任意方案:要求为:子序列元素乘积mod n为1;

赛时觉得结论为:子序列元素如果尽量都和n互素那么会是最好的取法吧,依照这个引理的话我们就很容易可以联想到所有和n互素的数都丢出来:
n = 9,那么最大互素集合就是1 2 4 5 7 8 这6个数;

又双叒叕可以联想到互素集合子集乘积一定是与n互素的。
那么依照上述引理可以简单分为两类:

1 答案为 ϕ ( n ) \phi(n) ϕ(n)
2 答案为 ϕ ( n ) − 1 \phi(n)-1 ϕ(n)1

如果是情况2,那么显然得到的最大与n互素集合乘积去掉就好。如12457*8 = 8 (mod 9
那么把8去掉剩下就是1了;显然1 2 4 5 7 就是答案。
如果答案为第一种那么也会有两种情况,一种是乘积已经是1,比如n = 2;另一种是乘积不为1,此时与引理相悖;

那就证明一下这个引理:(终于到了重头戏了)

设Ci表示答案序列的第i个元素
∑ C i = 1 + k n \sum{Ci} = 1+kn Ci=1+kn----------1
( 1 + k n , n ) = g (1+kn,n) = g (1+kn,n)=g-------------2
因为n%g = kn%g = 0;所以(1+kn)%g = 1;
如果g不为1,则式子无意义,故 ( 1 + k n , n ) = 1 (1+kn,n)=1 (1+kn,n)=1即二者一定互素;
有1式得Ci一定与n互素。
至此得证;
故可以放心使用前面引理推导出来极大集合。
同时乘积%n得到的数也会与n互素也易证得;
__C只需要证明出来剩下无难度,不放代码饿了;

D:结论+数据结构

问的是划分子序列让区间内所有子序列均满足cnt[max] <= (len+1)/2;
本结论非常易得,只需要考虑其中出现最多次数的数为X次,Y = len -x;
如果X<=Y+1那么答案为1,
否则需要思考,划分出来的子序列如何做到不浪费,当然是xi = yi+1拉,这样一个yi就能干掉比自己多一的数量的xi

如果拉伸到了极致,就是每一个子序列都长这样:
max max other
如此xi = 2,yi = 1的情况便是拉伸的极致。哦哦懂了每一个Y中的元素都能抵消两倍于自己的数;

结论 a n s ( l , r ) = m a x ( 1 , c n t [ m a x ] − Y ) ans(l,r) = max(1,cnt[max] - Y) ans(l,r)=max(1,cnt[max]Y);

问题转化成了如何求区间内出现最大次数的数出现了多少次;
此题可以用很多方法做,可以莫队水过去,可以整体二分+树状数组;

__D

### 完美排列问题分析 对于 Codeforces Round 1007 (Div. 2) 中的 **B. Perfecto** 问题,目标是找到一个长度为 \( n \) 的完美排列。如果这样的排列存在,则输出该排列;否则输出 `-1`。 #### 题目解析 题目定义了一个“完美排列”,其条件如下: - 对于任意位置 \( i \),满足 \( |p_i - p_{i+1}| = 1 \) 或者 \( |p_i - p_{i+1}| = n-1 \)[^2]。 这意味着相邻两个元素之间的差值要么等于 1(即连续),要么等于 \( n-1 \)(即首尾相连)。 #### 解题方法 通过观察和归纳可以得出以下结论: - 当 \( n \% 3 == 0 \) 或 \( n \% 3 == 2 \) 时,无法构建出符合上述条件的完美排列。 - 而当 \( n \% 3 == 1 \) 时,可以通过特定构造方式生成所需排列。 具体实现逻辑如下: ```cpp #include <bits/stdc++.h> using namespace std; void solve() { int n; cin >> n; if (n % 3 != 1) { // 如果不符合模数条件 cout << "-1\n"; return; } vector<int> res(n); bool flag = true; // 控制交替模式 for(int i = 0;i < n;i++) { if(flag){ res[i] = i + 1; } else{ res[i] = ((n-i)+1)%n; if(res[i]==0)res[i]=n; } flag=!flag; } for(auto num : res){ cout<<num<<" "; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); int t=1; while(t--){ solve(); } } ``` 此代码片段实现了基于输入大小 \( n \) 来判断是否存在合法解并输出相应结果的功能。 #### 关键点说明 - 判断依据来源于对不同余数值下能否形成循环结构的研究成果。 - 构造过程中采用交替填充策略来确保最终序列能够满足绝对差的要求。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值