CODEFORCE 998 DIV3
拖了好久,放假归来,终于可以把拖了很久的博客给写了。这场比赛都过去好长一段时间了,看来脱了很久了,所以现在补一下,算是一个补题的动力吧。
第一个题,属于简单题,直接暴力验证就可以了,当时因为python有一些比较友好的函数,避免了一些流程上的麻烦,所以我就直接使用python就可以解决了,一般会使用pypy,这样子比较快速,当然,pypy的栈空间不是特别大,所以对于高递归的不好处理,但是这道题不需要这么复杂,下面就是AC代码。
n=int(input())
from collections import Counter
for i in range(n):
a1,a2,a4,a5=map(int,input().split())
list1=[a1+a2,a4-a2,a5-a4]
a=Counter(list1).most_common()
print(a[0][1])
第二题,这个题有一点像一个归并排序的合并,但是我们在做这个题目的时候,不可以去直接像归并排序那样处理,但是这里我们有sort,只要把每一个牛有的牌给按照顺序排序就可以了,由于每一个只有2000个,所以排序的时间也是充足的,在这里,由于题目说了保障每一个数字都是依次递增的,所以说在这里只要按照顺序去搜索就可以了,找到了之后,把当前数字给弹出来,之后加入一个当前的位置信息到总和数组里面,最后对于这个数组遍历就可以了,检查每一个取模之后的结果是否相等就可以了。注意的是在弹出数字的时候一定要检查数组是否为空,所以不然会WA(因为这个浪费了一个小时+4发罚时)下面是AC的代码。
#include<bits/stdc++.h>
using namespace std;
inline void sol(){
vector<queue<int>> list1;
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
vector<int> v;
for(int j=1;j<=m;j++){
int num;scanf("%d",&num);
v.push_back(num);
}
sort(v.begin(),v.end());
queue<int> q;
for(int j:v){
q.push(j);
}
list1.push_back(q);
}
int num3=0;
vector<int> num2;
while(num3<n*m){
for(int i=0;i<n;i++){
if(list1[i].size()!=0 && list1[i].front()==num3){
list1[i].pop();
num2.push_back(i+1);
num3++;
}
}
}
bool flag=true;
for(int i=0;i<num2.size();i++){
if (num2[i]!=num2[i%n]){
flag=false;
break;
}
}
if (flag){
for(int i=0;i<n;i++){
cout<<num2[i]<<" ";
}
cout<<endl;
}
else{
cout<<"-1"<<endl;
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
sol();
}
}
第三题,这个是一个虚假的博弈论的题目。里面说一个人想让数字选择争取a+b=k 另一个要求 a+b!=k,但是在这里,如果仔细观察样例,就会发现,其实输出的结果就是有多少对数字可以使a+b=k,不存在什么博弈的情况,所以直接排序后双指针结束了,下面是AC代码
#include<bits/stdc++.h>
using namespace std;
inline void sol(){
int n,k;scanf("%d %d",&n,&k);
vector<int> v;
for(int i=0;i<n;i++){
int x;scanf("%d",&x);
v.push_back(x);
}
sort(v.begin(),v.end());
int l=0;int r=n-1;
int res=0;
while(l<r){
if(v[l]+v[r]<k){
l++;
}
else if (v[l]+v[r]>k){
r--;
}
else{
l++;
r--;
res++;
}
}
cout<<res<<endl;
}
int main(){
int T;scanf("%d",&T);
while(T--){
sol();
}
}
第四题,一开始看到觉得头大,后来才发现原来两个数字必须是相互挨着的,这时题目就变得简单太多了,于是就直接for循环平推过去,然后再去检查最后的结果,然后就可以AC了,C,D两题整体难度不大,但是B题浪费太多时间,算是比赛的遗憾。如下是AC的代码
#include<bits/stdc++.h>
using namespace std;
inline void sol(){
int n;scanf("%d",&n);
vector<int> v;
for(int i=0;i<n;i++){
int a;scanf("%d",&a);
v.push_back(a);
}
for(int i=0;i<n-1;i++){
int num=min(v[i],v[i+1]);
v[i]-=num;
v[i+1]-=num;
}
bool flag=true;
for(int i=1;i<n;i++){
if(v[i]>=v[i-1]){
continue;
}
else{
flag=false;
break;
}
}
if(flag){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
int main(){
int T;scanf("%d",&T);
while(T--){
sol();
}
}
然后是第五题,这后面的题没有时间做了,所以就按照答案来讲。
首先,题目会输入n,m1,m2分别表示n个点,F图里面有m1个边,G图里面有m2个边,在这里,题目要求的是对图F进行删除边和增加边两种操作,然后使F存在一条边当且仅当G中存在一个相同的边。
那么首先,我们需要排除掉所有G中不存在,但是F存在的边,在找到这样子的边之后,移除这一条边,如此去掉多余的边之后,此时就是要通过添加边来保证连通性是一样的,即联通分量一样,那么在这里,由于要保证联通分量一样,那么只要在操作两个联通分量的数量只差次就可以了,因为在这里,F图所拥有的边,一定是G已经拥有的,所有此时只要去增加即可。
下面是AC代码。
#include<bits/stdc++.h>
using namespace std;
void Gdfs(int v,vector<vector<int>> &sl,vector<int> &col,int c){
col[v]=c;//将v节点染色为c
for(int u:sl[v]){//遍历c的每一个邻接节点u
if(col[u]==0){//若是u没有被染色,那么就对u染色
Gdfs(u,sl,col,c);
}
}
}
//old col表示旧的染色信息,这个信息是用来做参考的
int Fdfs(int v,vector<vector<int>> &sl,vector<int> &col,vector<int>
&old_col,int c){
col[v]=c;//将v染色味c
int res=0;
for(int u:sl[v]){
if(col[u]==0){
if (old_col[u]!=c){//如果u并没有被染色c,那么就让res++
res++;
}
else{//否则就继续往下搜索所有的节点来染色
res+=Fdfs(u,sl,col,old_col,c);
}
}
}
return res;
}
void read_con_list(vector<vector<int>> &sl,int m){
//构建邻接表
for(int i=0;i<m;i++){
int u,v;
scanf("%d %d",&u,&v);
//保证是从0开始
sl[--u].emplace_back(--v);
sl[v].emplace_back(u);
}
}
void sol(){
int n,mf,mg;
scanf("%d %d %d",&n,&mf,&mg);
vector<vector<int>> fsl(n),gsl(n);
read_con_list(fsl,mf);
read_con_list(gsl,mg);
vector<int> fcol(n),gcol(n);
int ans=0;//记录最后的结果
for(int i=0;i<n;i++){ //遍历所有的节点,对其进行染色。
if(gcol[i]==0){//0表示未被染色
Gdfs(i,gsl,gcol,i+1);//i+1表示被染上i+1颜色
}
if(fcol[i]==0){
//f中当前节点未被染色
ans+=Fdfs(i,fsl,fcol,gcol,gcol[i]);//以g为参考的时候,如果两个点连接的联通分量不同,那么会为ans
if (gcol[i]<i+1){//若是当前染色是和他不一样,表示需要怎家一下边
ans++;
}
}
}
cout<<ans<<endl;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
sol();
}
return 0;
}
然后是G题,F题没有C++的代码,所以就不想补了,直接看G题
G题是首先给了两个数组,然后通过对a[i],b[j]和a[j],b[i]交换,通过这样子的方式实现a数组和b数组两个数组都是升序的。题目要回答这两个数组是否可以实现这样子的情况。
在这里,首先对于每一个数对(a[i],b[i])来说,按照min(a[i],b[i])的顺序完成排序,
关于按照min(a[i],b[i])来排序的必要性证明,在这里,使用反证法来证明,首先假设存在一个数对(a[i],b[i]),满足a[i]<b[i],并且a[i]小于前一个数对的最小元素。
在最终的排序中,数对是有序排序的,若是要把数对(a[i],b[i])放在钱一个数对之后,由于a[i]会小于前面数对中的元素,影响到整体升序的原则,所以必须按照min(a[i],b[i])来升序排序。
接下来通过判断是否可以通过翻转数对来实现排序,这里,通过使用动态规划来解决问题。
这里dp的设定如下,有4种情况
1.若是可以使用偶数次翻转将第i个数对(包括第i个数对)及其之前的数对排序,且第i个数对不翻转,那么dp[1][i]=1;
2.若是可以使用偶数次翻转将第i个数对(包括第i个数对)及其之前的数对排序,且第i个数对翻转,那么dp[2][i]=1;
3.若是可以使用奇数次翻转将第i个数对(包括第i个数对)及其之前的数对排序,且第i个数对不翻转,那么dp[2][i]=1;
4.若是可以使用奇数次翻转将第i个数对(包括第i个数对)及其之前的数对排序,且第i个数对翻转,那么dp[3][i]=1;
这里的翻转是指将(a,b)变换成为(b,a)的意思。
在这里对于状态转移的方程,则是要讨论两种情况,分别为不翻转第i个数字就可以和前一个数字保持递增关系,另一种,则是表示从前一个数对的相反的奇偶性和翻转的状态转移过来。所以这两种情况需要分开处理。
最后AC的代码如下所示
#include<bits/stdc++.h>
using namespace std;
#define print pair<int,int>
#define vp vector<print>
#define ALL(x) (x).begin(), (x).end()
void sol(){
int n;scanf("%d",&n);
vp pairs(n);
for(int i=0;i<n;i++){
scanf("%d",&pairs[i].first);
}
for(int i=0;i<n;i++){
scanf("%d",&pairs[i].second);
}
//对于数对(a,b)在这里按照最小的数字来进行排序
sort(ALL(pairs), [](print a, print b)
{ return min(a.first, a.second) < min(b.first, b.second); });
vector<vector<int>> dp(4,vector<int>(n,0));
dp[0][0]=1;
dp[3][0]=1;
//判断这样子的排序是否可以通过交换来实现
for(int i=1;i<n;i++){
//如果这个位置是有序的,那么说明这里没有发生交换
if(pairs[i-1].first<pairs[i].first and pairs[i-1].second<pairs[i].second){
dp[0][i] |=dp[0][i-1];
dp[1][i] |=dp[1][i-1];
dp[2][i] |=dp[3][i-1];
dp[3][i] |=dp[2][i-1];
}
//如果这个地方是无序的,那么说明这里发生了一次交换
if(pairs[i-1].first<pairs[i].second and pairs[i-1].second<pairs[i].first){
dp[0][i] |=dp[2][i-1];
dp[1][i] |=dp[3][i-1];
dp[2][i] |=dp[1][i-1];
dp[3][i] |=dp[0][i-1];
}
}
//
if ((dp[0][n-1] | dp[2][n-1])){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
sol();
}
return 0;
}
就到这里了。
本文作者:芙芙芙啊
本文链接:https://www.cnblogs.com/fufufuf/p/18697081
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步