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) 个人题解相关推荐

  1. Codeforces Round #686 (Div. 3) A-F题解

    Codeforces Round #686 (Div. 3) A-F题解 A. Special Permutation 题意 给定 nnn ,输出一个长度为 nnn 的全排列,每个位置 iii 上的数 ...

  2. Codeforces Round #693 (Div. 3)部分题解

    Codeforces Round #693 (Div. 3) 部分题解 D. Even-Odd Game 思路: 贪心:田忌赛马 (1)先将数组从大到小排序,取数时从大到小取,用一个ans变量记录取数 ...

  3. Codeforces Round #702 (Div. 3)A-G题解

    Codeforces Round #702 (Div. 3)A-G题解 比赛链接:https://codeforces.ml/contest/1490 这场F读错题意白给一发,G二分的if(dp[mi ...

  4. codeforces Round #645 (Div. 2)D题解

    Codeforces Round #645 (Div. 2)--D题解 作为一名菜鸡,理所当然得没有A出来,这道题数据放小就一水题了,可惜数据这块卡的死死的. 本题最重要的一点就是你要推出来一个结论: ...

  5. Codeforces Round #670 (Div. 2)A-D题解

    Codeforces Round #670 (Div. 2)A-D题解 //写于rating值1987/2184 //补档 比赛链接:https://codeforces.ml/contest/140 ...

  6. Codeforces Round #674 (Div. 3)A-F题解

    Codeforces Round #674 (Div. 3)A-F题解 比赛链接:https://codeforces.com/contest/1426 A题 水题不写题解 #include<b ...

  7. Codeforces Round #807 (Div. 2) A-C题解

    Codeforces Round #807 (Div. 2) A.B.C题题解 A - Mark the Photographer 题意:马克要给2n个人照相,分两排,一排站n人,给出每个人的身高,要 ...

  8. Codeforces Round #723 (Div. 2) 个人题解

    上1400辣! 传送门:https://codeforces.com/contest/1526 A. Mean Inequality 题意 给一个长度为偶数的数组,你需要重排这个数组,使得任意一个数不 ...

  9. Codeforces Round #710 (Div. 3)个人题解

    Codeforces Round #710 (Div. 3) 文章目录 [Codeforces Round #710 (Div. 3)](https://codeforces.com/contest/ ...

最新文章

  1. 约瑟夫生死环游戏c语言程序,使用C++实现的约瑟夫生死游戏
  2. 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)
  3. 为什么不同的深度学习框架要使用不同的保存格式(转)
  4. SAP云平台上的ABAP编程环境能做哪些事情
  5. 004. ES6之函数的扩展
  6. ubuntu16.04 安装图像界面,设置自动登录以及取消休眠模式
  7. 测试freenas9.1搭建iscsi磁盘库
  8. ---Ubuntu 下安装oracle Java
  9. 常用plc编程软件阵营划分
  10. 坐火车硬座20小时是怎样的体验?
  11. IT项目管理之第5章 项目时间管理习题之选择题汇总
  12. 蔡氏电路matlab仿真实代码验,基于蔡氏电路的MATLAB仿真
  13. 每天学命令write_ldb
  14. 第19章 数据库备份与恢复
  15. Unity 中 创建 TextMeshPro 中文字体(含常见汉字 TXT 文件)
  16. 2022年黄石市高企申报奖励补贴以及认定奖励补贴汇总!
  17. 自用笔记17——泰波那契数列
  18. 超时锁定计算机,Win10电脑设置锁定屏幕超时怎么办
  19. service暴露端口的方式与代理方式
  20. PWN-COMPETITION-HGAME2022-Week2

热门文章

  1. Http Multipart报文格式
  2. C++的继承,封装,多态
  3. IDEA中的maven阿里仓库配置
  4. 神经网络实战记录11—调参技巧2—fine-tune(基于VGGNet tensorboard代码改)
  5. 教你一招通过注册表一键开启/禁用USB端口
  6. Mapbox 地图 生成矢量数据圆
  7. 宁德市计算机应用能力考试时间,福建省宁德市私募考试
  8. 麒麟820 soc鸿蒙系统,麒麟820是集成基带吗
  9. vue钩子函数beforeRouteEnter
  10. (转载)浅析ODS与EDW 关系