Codeforces Round #842 (Div. 2) 个人题解
A. Greatest Convex
题意:
给t组数据,每组数据给定一个k,求出在[1,k)范围内,满足x!+(x-1)!%k==0的最大x
题解:
赛中可以通过观察法得知输出k-1即可,赛后可以尝试证明
实际上对于x!+(x-1)!,取x为k-1,则有x!+(x-1)!=1*2*3*...*(k-2)*(k-1)+1*2*3*...*(k-2)
不难发现提取公因式后,原式可以化简为:x!+(x-1)!=1*2*3*...*(k-2)*k
此式一定可以被k整除,所以每组数据直接输出k-1即可。
本题代码:
过于简单所以略。
B. Quick Sort
题意:
给t组数据,每组数据给定一个n,一个k和一个长度为n的乱序的排列,你每次可以选择k个元素将他们从数组中拿出,并且排好序放在数组的最后,求让数组升序的最小操作次数。
题解:
由题可知,每次操作都会把元素移出并且放到最后,不难想到一种贪心策略:
从1开始,根据原始顺序有序的最长序列可以不用动(中间可以隔有其他元素)。
如n=8,数组为{1,6,4,2,7,8,3,5}时,最长序列就为{1,2,3}
数组中的1,2,3元素是可以不用操作的,移出其他乱序的元素,1,2,3就会自然有序,利用反证法,如果移动其中任一元素,比如1,所以可以得到如下算法:
记录每个元素的下标mp[i],找到最长的有序串,即最大的i(记为pos)使得mp[i]>mp[i-1],那么需要操作的元素个数就为n-pos个,操作次数就为(n-pos+k-1)/k。
本题代码:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
#include<set>
#include<queue>
typedef long long ll;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const int N = 5E5 + 7;
using namespace std;
ll ksm(ll a,ll b) {ll res=1;a%=mod; while(b){if(b&1)res=res*a%mod;b>>=1;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll inv(ll x) {return ksm(x, mod-2);}
int mp[N];
void solve(){int n,k;cin>>n>>k;vector<int>v(n);for(int i=1;i<=n;i++) {cin >> v[i - 1];mp[v[i-1]]=i;}int pos=1;for(int i=2;i<=n;i++){if(mp[i]>mp[i-1])pos=i;else break;}ll ans=(n-pos+k-1)/k;cout<<ans<<'\n';
}
int main(){int t=1;cin>>t;while(t--)solve();
}
C. Elemental Decompress
题意:
给t组数据,每组数据给定一个n和长度为n的序列a,要求构造两个长度同样为n的排序p,q,使得
ai=max(pi,qi),如果能够构造出这样的序列,输出YES并输出两个序列,不能则输出NO。
题解:
首先判断构造不出的情况,很明显,某个元素出现3次及以上肯定构造不出,特别的,因为没有元素小于1,所以1最多出现一次。
再来构造p和q,贪心的思路,不妨把序列a中的元素尽量从p中拿(这对结果并没有影响),除非当前元素p中已经放过了,才放入q中,代码表现为:
for(int i=1;i<=n;i++)if(!vis1[v[i]])a[i]=v[i],vis1[v[i]]=1;else b[i]=v[i],vis2[v[i]]=1;
然后,我们可以知道对于还没有填元素的位置,要么p[i]是空的,要从q还没用过的元素中取,要么q[i]是空的,要从p还没用过的元素中取,namo,怎么取元素最合适呢?如p[i]=4时,q没用过的元素中有4和1,当然是选4而不是1,因为1比4能满足更多个p[i],我们该选择满足最低限度的元素,主打的就是一个贪心。
你可以通过线段树查询<=p[i]的最大元素填入,但是对于1300分的题目多少有点大材小用,开个pair数组记录p[i](q[i])和他们对应的位置,然后复制一份并且排序,然后把没有用过的元素存入优先队列,对每一个值选择满足最低限度的值(这个值就是优先队列的top),如果没有满足要求的值,那么说明构造不出这样的序列,退出即可。
本题代码:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
#include<set>
#include<queue>
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const int N = 2E6 + 7;
using namespace std;
ll ksm(ll a,ll b) {ll res=1;a%=mod; while(b){if(b&1)res=res*a%mod;b>>=1;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll inv(ll x) {return ksm(x, mod-2);}
void solve(){int n;cin>>n;vector<int>cnt(n+1),vis1(n+1),vis2(n+1);vector<int>v(n+1),a(n+1),b(n+1);vector<pair<int,int>>pv1(1),pv2(1);for(int i=1;i<=n;i++)cin>>v[i],cnt[v[i]]++;for(auto it:v)if(cnt[it]>2||cnt[1]>1){cout<<"NO"<<'\n';return;}priority_queue<int,vector<int>,greater<>>q1,q2;for(int i=1;i<=n;i++)if(!vis1[v[i]])a[i]=v[i],vis1[v[i]]=1,pv1.push_back({a[i],i});else b[i]=v[i],vis2[v[i]]=1,pv2.push_back({b[i],i});for(int i=1;i<=n;i++) {if (!vis1[i])q1.push(i);if (!vis2[i])q2.push(i);}sort(pv1.begin(),pv1.end());sort(pv2.begin(),pv2.end());for(int i=1;i<pv1.size();i++){if(pv1[i].first>=q2.top())b[pv1[i].second]=q2.top(),q2.pop();else{cout<<"NO"<<'\n';return;}}for(int i=1;i<pv2.size();i++){if(pv2[i].first>=q1.top())a[pv2[i].second]=q1.top(),q1.pop();else{cout<<"NO"<<'\n';return;}}cout<<"YES"<<'\n';for(int i=1;i<=n;i++)cout<<a[i]<<' ';cout<<'\n';for(int i=1;i<=n;i++)cout<<b[i]<<' ';cout<<'\n';
}
int main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);int t=1;cin>>t;while(t--)solve();
}
D.Lucky Permutation
题意:
给出一个排列,你可以任意选择两个元素交换,求至少交换多少次能让序列中有且仅有一组逆序对。
题解:
首先,如果序列中仅有一对逆序对,那么这对逆序对一定是相邻的,我们可以考虑将序列变为有序后选择一对相邻元素交换。
先引入一个概念:置换环:对于升序的排列,肯定存在v[i]=i,也就是下标(i)和数值(v[i])相等,如果一个排列中存在有数值不等于位置,即v[i]!=i,同理就有下标v[i]和数值v[v[i]]不相等。
通俗的说:如果3的位置上不放3放了8,那么8的位置上肯定不会放着8,放了其他数字。
我们不断的去找当前数值指向的下一个位置,最终一定会指向最开始的位置,形成一个环。
如{1,7,5,8,2,6,3,4}
可以被拆分成{1},{7,3,5,2},{8,4},{6}这样四个环。
代码表现就是:
int now=i,head=i;//now当前节点,v[now]是下一个节点int len=1;//cnt为环上有几个元素(环的长度) while(v[now]!=head){len++;now=v[now];}
namo,对于一个环,易得它可以帮我减少一次交换次数(环形交换,最有一个元素自动归位)
仅仅是排成有序序列的话我们只要计算n-cnt即可(cnt为环的个数),但是我们要保证有一对逆序对,所以说在遍历一个环的时候,我们要记录是否有相邻元素逆序对出现,如果有的话,我们不用换成有序,
少换一次就有一对逆序对出现了,以下是代码实现
本题代码:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
#include<set>
#include<queue>
#define eol "\n"
typedef long long ll;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const int N = 2E6 + 7;
using namespace std;
ll ksm(ll a,ll b) {ll res=1;a%=mod; while(b){if(b&1)res=res*a%mod;b>>=1;a=a*a%mod;}return res%mod;}
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll inv(ll x) {return ksm(x, mod-2);}
void solve(){int cnt=0,res=-1,n;cin>>n;vector<int>v(n+1);vector<int>vis(n+1);for(int i=1;i<=n;i++)cin>>v[i];for(int i=1;i<=n;i++){cnt+=(!vis[i]);if(!vis[i]){int now=i,head=i;//now当前节点,v[now]是下一个节点map<int,int>mp;while(v[now]!=head){vis[now]=mp[v[now]]=1;if(mp[v[now]-1]||mp[v[now]+1])res=1;now=v[now];}vis[now]=mp[v[now]]=1;if(mp[v[now]-1]||mp[v[now]+1])res=1;}}cout<<n-cnt-res<<eol;
}
int main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);int t=1;cin>>t;while(t--)solve();
}
E. Partial Sorting
题意:
给出n和模数M,求长度为3n的排列变成升序的最小操作次数,对于一个排列,你有两种操作,第一种,排序前2n个数,第二种,排序后2n个数,你要输出的是所有满足长度为3n的排序的操作次数之和
题解:
为了方便表述,排列中i=v[i]我就称其已配对
让一个序列有序,最多只需要两次操作:
0次的:本身就有序
令条件a为前n个数配对,条件b为后n个数配对
1次的:a,b满足并且只满足一个
令条件c为小于等于n的数值分布在前2n的位置 条件d为大于n的数值分布在后2n的位置
2次的:c,d满足并且只满足一个
3次的:c,d同时不满足
然后我们开始排列组合和容斥!
0次的:
只有一组
1次的:
前n配对:后2n个元素随意排列,后n配对,前2n个元素随意排列
减去重复统计的,即a,b条件都满足的,也就是前n后n都配对,中间n个随意排列
所以答案为种
2次的:
选取前n个元素,在2n个位置里排列也就是A(2n,n)
选取后n个元素,在后2n个位置里排列,同上是A(2n,n)
剩下2n个数随意排列是(2n)!
然后减去重复统计的,即同时满足c,d条件的:
枚举前n个元素在后n个位置里出现的个数i,那么后n个元素能放的位置只有2n-i个,剩下n个随意排列,推推式子吧大伙:
3次的:
看起来啥条件都不满足,没规律很一般很难搞,但是你前面都容斥这么久了还没反应过来?你其他的算出来了,剩下一种减一下不就出来了?
最后对整体进行容斥
只3次的=3次的-2次的
只2次的=2次的-1次的
只1次的= 1次的-0次的
加起来就是答案了
上代码:
本题代码:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
#include<set>
#include<queue>
#define eol "\n"
typedef long long ll;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int N = 2E6 + 7;
using namespace std;
ll n,mod;
ll ksm(ll a,ll b) {ll res=1;a%=mod; while(b){if(b&1)res=res*a%mod;b>>=1;a=a*a%mod;}return res%mod;}
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll inv(ll x) {return ksm(x, mod-2);}
ll fac[5000005],ifac[5000005];
void jc(int n){fac[0]=1;for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;ifac[n]=ksm(fac[n],mod-2);for(int i=n-1;i>=0;i--)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
}
ll C(int n,int m){if(n<m) return 0;return (1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod)%mod;
}
void solve(){cin >> n >> mod;jc(3 * n+1);vector<ll>num(4);num[0] = 1;num[1] = (2 * fac[2*n]%mod - fac[n]+mod)%mod;num[2] =( 2 * fac[n]* C(2ll*n, n) % mod * fac[2*n] % mod)%mod;ll temp = (fac[n] * fac[n] )% mod * fac[n] % mod;for(int i = 0; i <= n; i++) {num[2] -= C(n, i) * C(n, n - i) % mod * C(2 * n - i, n - i) % mod * temp % mod;num[2] = ((num[2] % mod) + mod) % mod;}num[3]=fac[n*3]%mod;for(int i=3;i>=1;i--)((num[i]-=num[i-1])+=mod)%=mod;ll ans=0;for(int i=0;i<=3;i++)ans=((ans+(num[i]*i%mod))%mod+mod)%mod;cout<<ans<<eol;
}
int main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);int t=1;//cin>>t;while(t--)solve();
}
Codeforces Round #842 (Div. 2) 个人题解相关推荐
- Codeforces Round #686 (Div. 3) A-F题解
Codeforces Round #686 (Div. 3) A-F题解 A. Special Permutation 题意 给定 nnn ,输出一个长度为 nnn 的全排列,每个位置 iii 上的数 ...
- Codeforces Round #693 (Div. 3)部分题解
Codeforces Round #693 (Div. 3) 部分题解 D. Even-Odd Game 思路: 贪心:田忌赛马 (1)先将数组从大到小排序,取数时从大到小取,用一个ans变量记录取数 ...
- Codeforces Round #702 (Div. 3)A-G题解
Codeforces Round #702 (Div. 3)A-G题解 比赛链接:https://codeforces.ml/contest/1490 这场F读错题意白给一发,G二分的if(dp[mi ...
- codeforces Round #645 (Div. 2)D题解
Codeforces Round #645 (Div. 2)--D题解 作为一名菜鸡,理所当然得没有A出来,这道题数据放小就一水题了,可惜数据这块卡的死死的. 本题最重要的一点就是你要推出来一个结论: ...
- Codeforces Round #670 (Div. 2)A-D题解
Codeforces Round #670 (Div. 2)A-D题解 //写于rating值1987/2184 //补档 比赛链接:https://codeforces.ml/contest/140 ...
- Codeforces Round #674 (Div. 3)A-F题解
Codeforces Round #674 (Div. 3)A-F题解 比赛链接:https://codeforces.com/contest/1426 A题 水题不写题解 #include<b ...
- Codeforces Round #807 (Div. 2) A-C题解
Codeforces Round #807 (Div. 2) A.B.C题题解 A - Mark the Photographer 题意:马克要给2n个人照相,分两排,一排站n人,给出每个人的身高,要 ...
- Codeforces Round #723 (Div. 2) 个人题解
上1400辣! 传送门:https://codeforces.com/contest/1526 A. Mean Inequality 题意 给一个长度为偶数的数组,你需要重排这个数组,使得任意一个数不 ...
- Codeforces Round #710 (Div. 3)个人题解
Codeforces Round #710 (Div. 3) 文章目录 [Codeforces Round #710 (Div. 3)](https://codeforces.com/contest/ ...
最新文章
- 约瑟夫生死环游戏c语言程序,使用C++实现的约瑟夫生死游戏
- 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)
- 为什么不同的深度学习框架要使用不同的保存格式(转)
- SAP云平台上的ABAP编程环境能做哪些事情
- 004. ES6之函数的扩展
- ubuntu16.04 安装图像界面,设置自动登录以及取消休眠模式
- 测试freenas9.1搭建iscsi磁盘库
- ---Ubuntu 下安装oracle Java
- 常用plc编程软件阵营划分
- 坐火车硬座20小时是怎样的体验?
- IT项目管理之第5章 项目时间管理习题之选择题汇总
- 蔡氏电路matlab仿真实代码验,基于蔡氏电路的MATLAB仿真
- 每天学命令write_ldb
- 第19章 数据库备份与恢复
- Unity 中 创建 TextMeshPro 中文字体(含常见汉字 TXT 文件)
- 2022年黄石市高企申报奖励补贴以及认定奖励补贴汇总!
- 自用笔记17——泰波那契数列
- 超时锁定计算机,Win10电脑设置锁定屏幕超时怎么办
- service暴露端口的方式与代理方式
- PWN-COMPETITION-HGAME2022-Week2