Codeforces Round #839 (Div. 3)

本文介绍了四道编程竞赛题目,涉及数学、排序、矩阵旋转和游戏策略等算法。第一题要求计算a+b的值,第二题询问如何旋转矩阵使得行和列首元素均严格递增,第三题构建序列最大化相邻元素差异数,第四题通过操作数组实现排序,第五题分析游戏双方获胜条件,第六题还原矩阵操作过程,最后是根据评分变化预测比赛次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. A+B?

题意:

t组测试每组给出以a+b的形式给出算式,求a+b的值。(a,b都是0~9)

代码:

t=int(input())
for i in range(t):
    s=input()
    print(eval(s))

B. Matrix Rotation

题意:

t组测试每组给一个2*2的矩阵,你可以把矩阵顺时针旋转90度(可以做多次)。问能否使得矩阵满足对于每一行和每一列第一个元素都小于第二个元素。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list> 
#include <algorithm>
#define pii pair<int,int>
#define se second
#define fi first
#define rep(i,a,b) for (int i=a;i<b;++i)
#define per(i,a,b) for (int i=a;i>b;--i)
#define mid ((l+r)>>1)
#define lson(root) ((root)<<1)
#define rson(root) (((root)<<1)|1)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define endl '\n'
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const LL INF=0x3f3f3f3f;
const LL MOD=1e9+7;
const int N=3003;
const int M=3003;

void solve(){
    int flag=0;
    int a,b,c,d;
    cin>>a>>b>>c>>d;

    if (a<b && c<d && a<c && b<d) flag=1;
    if (c<a && d<b && c<d && a<b) flag=1;
    if (d<c && b<a && d<b && c<a) flag=1;
    if (b<d && a<c && b<a && d<c) flag=1;

    if (flag) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;

    return ;
}

int main(){
    #ifndef ONLINE_JUDGE
        freopen("title.in","r",stdin);
        freopen("title.out","w",stdout);
    #endif
    // ios::sync_with_stdio(false);
    // cin.tie(0);cout.tie(0);
    int _=1;
    cin>>_;
    // cout<<_<<endl;
    // scanf("%d",&_);
    while (_--) solve();
    // rep(i,1,_+1){
    //     cout<<"Case "<<i<<": ";
    //     solve();
    // }
    return 0;
}   

C. Different Differences

题意:

t(1≤t≤819)组测试每组给定k和n (2≤k≤n≤40),构造一个含有k个元素的严格递增序列a,1<=ai<=n,使得序列[a2−a1,a3−a2,…,ak−ak−1]所包含不同数的个数最多。

思路:

就是要求相邻数距离的不同个数最大。如果n=k,只能构造1,2,3...n,相邻数之间的距离都为1;如果n-k=1,就可以把一个距离改为2,得到不同个数多一个;若n-k=3,把一个距离改为2,一个改为3,得到不同个数为3。由此类推可知如果n-k刚好是t*(t+1)/2的形式,可以得到t+1个不同的个数。

首先找出t*(t+1)<=2*(n-k)最大的t,说明最多可以修改多少个距离。先构造前t+1个数,即1,3,6,10...i*(i+1)/2。这样保证达到最大不同个数了,后面就递增构造就可以了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list> 
#include <algorithm>
#define pii pair<int,int>
#define se second
#define fi first
#define rep(i,a,b) for (int i=a;i<b;++i)
#define per(i,a,b) for (int i=a;i>b;--i)
#define mid ((l+r)>>1)
#define lson(root) ((root)<<1)
#define rson(root) (((root)<<1)|1)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define endl '\n'
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const LL INF=0x3f3f3f3f;
const LL MOD=1e9+7;
const int N=45;
const int M=3003;
int a[45];
void solve(){
    int k,n;
    cin>>k>>n;
    int t=n-k,d=0;
	while(d*(d+1)<=2*t) ++d;
	rep(i,1,d+1) a[i]=i*(i+1)/2;
	rep(i,d+1,k+1) a[i]=a[i-1]+1;
	rep(i,1,k+1) cout<<a[i]<<" ";
	cout<<endl;
    return ;
}
int main(){
    #ifndef ONLINE_JUDGE
        freopen("title.in","r",stdin);
        freopen("title.out","w",stdout);
    #endif
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int _=1;
    cin>>_;
    // cout<<_<<endl;
    // scanf("%d",&_);
    while (_--) solve();
    // rep(i,1,_+1){
    //     cout<<"Case "<<i<<": ";
    //     solve();
    // }
    return 0;
}

D. Absolute Sorting

题意:

t组(1≤t≤2⋅10^4)测试,每组给定长度为n(2≤n≤2⋅10^5)的数组a(1≤ai≤10 ^8)。只能进行一次操作,选一个数,把每个ai变成|ai-x|。问x是多少的时候可以将a排好序(即a1≤a2≤⋯≤an)。不存在输出-1.

思路:

考虑序列中的逆序对ai>aj (i<j),考虑x至少为多少才能使得ai>=aj。此时x一定会比aj大,如果x大于ai显然满足,我们考虑x<=ai的情况,去掉绝对值就是:

a_{i}-x<=x-a_{j}

即:x\geq \left \lceil \frac{a_{i}+a_{j}}{2} \right \rceil

对于一个所有的逆序对都需要满足上式,所有求出ai+aj最大的逆序对就是x的最小值,用归并就可以做。求出后在求出操作后的a检查一遍合不合法就可以了。

为什么x要尽量选小的?因为ai<aj (i<j),x不能超过\left \lceil \frac{a_{i}+a_{j}}{2} \right \rceil,否则就变成逆序对了。所以越小越好。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list> 
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second 
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const int N=2e5+10;
int a[N],b[N],c[N],mx;
void merge(int l,int r)
{
	if(l>=r) return;
	int mid=l+r>>1;
	merge(l,mid),merge(mid+1,r);
	int i=l,j=mid+1;
	rep(k,l,r+1)
		if(j>r||i<=mid&&c[i]<=c[j]) b[k]=c[i++];
		else{
			if(mid-i+1>0) mx=max(mx,(c[mid]+c[j])/2+(c[mid]+c[j])%2);
			b[k]=c[j++];
		}
	rep(k,l,r+1) c[k]=b[k];
}
void solve()
{
	int n;
	cin>>n;
	rep(i,0,n) cin>>a[i],c[i]=a[i];
	mx=0;
	merge(0,n-1);
	if(mx==0){
		cout<<0<<endl;
		return;
	}
	rep(i,0,n) a[i]=abs(a[i]-mx);
	rep(i,1,n){
		if(a[i-1]>a[i]){
			cout<<-1<<endl;
			return;
		}
	}
	cout<<mx<<endl;
}
int main()
{
	#ifndef ONLINE_JUDGE
		freopen("title.in","r",stdin);
		freopen("title.out","w",stdout);
	#endif
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int _=1;
	cin>>_; 
	while(_--){
		solve();
	}
	return 0;
}

E. Permutation Game

题意:

给定一个n的排列,两个人玩游戏,第一个人使排列变成正序获胜,第二个人使排列变成倒序获胜,初始所有数都是红色,且保证没有排好的情况。每一轮一个人可以:1.把所有蓝色位置上的数字重新排列。2.选择一个红色的把它改成蓝色。3.什么都不做。

输出获胜情况。

思路:

如果一个玩家要把序列排成有序,必须要把不正确的位置的数都改成蓝色,其他数改不改都无所谓,只要是蓝色的数就可以任意交换次序。问题转换成两个人谁先把自己需要改成蓝色的数选完。

对于一个玩家来说,他会选择一个位置不正确的且为红色的把它改为蓝色,如果存在一些位置是另外一个玩家也希望修改的,最优策略必然是尽量先避免选择这种公共的位置。因为这种位置可以等着另外一个玩家去修改,而非公共位置只能自己修改。

统计玩家1和玩家2需要修改的数目和公共修改的数目,按照这个策略模拟一遍即可。也可以推公式直接判断,但没必要。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list> 
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second 
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const int N=5e5+10;
int a[N];
void solve()
{
	int n,cnt1=0,cnt2=0,cnt=0;
	cin>>n;
	rep(i,1,n+1){
		cin>>a[i];
		if(a[i]!=i) ++cnt1;
		if(a[i]!=n-i+1) ++cnt2;
		if(a[i]!=i&&a[i]!=n-i+1) ++cnt;
	}
	for(int i=1;;++i){
		if(cnt1==0&&cnt2==0){
			cout<<"Tie"<<endl;
			return;
		}
		if(cnt1==0){
			cout<<"First"<<endl;
			return;
		}
		if(cnt2==0){
			cout<<"Second"<<endl;
			return;
		}
		if(i&1){
			if(cnt1>cnt) --cnt1;
			else --cnt1,--cnt2,--cnt;
		}else{
			if(cnt2>cnt) --cnt2;
			else --cnt1,--cnt2,--cnt;
		}
	}
}
int main()
{
	#ifndef ONLINE_JUDGE
		freopen("title.in","r",stdin);
		freopen("title.out","w",stdout);
	#endif
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int _=1;
	cin>>_; 
	while(_--){
		solve();
	}
	return 0;
}

F. Copy of a Copy of a Copy

题意:

一个n*m的0-1矩阵,每一次操作可以:1.选一个(x,y),它的上下左右都和它相反,且不为边界,可以把(x,y)改为相反的。2.复杂当前的图像。

给定k个复制出来的图和原图(顺序不确定),需要还原操作过程,确定原图是哪一个以及每一步复制的k是哪一个。

3≤n,m≤30; 0≤k≤100

思路:

如果对一个图进行了操作,这个图的合法操作数一定是减少的。统计所有图的合法操作个数,按照降序排列,第一个图作为原图,后面的图和前面一个做比较,不相同的坐标就是修改的坐标。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list> 
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define pip pair<int,pii>
#define se second 
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const int N=35;
int n,m,k;
struct node{
	string s[N];
	int id,cnt;
}g[110];
int get_cnt(int u)
{
	int res=0;
	rep(i,2,n)
	rep(j,2,m){
		int x=g[u].s[i][j]-'0';
		if(g[u].s[i+1][j]-'0'==1-x&&g[u].s[i-1][j]-'0'==1-x&&g[u].s[i][j-1]-'0'==1-x&&g[u].s[i][j+1]-'0'==1-x) ++res;
	}
	return res;
}
bool cmp(node a,node b)
{
	return a.cnt>b.cnt;
}
void solve()
{
	cin>>n>>m>>k;
	rep(i,1,k+2){
		g[i].id=i;
		rep(j,1,n+1) cin>>g[i].s[j],g[i].s[j]='0'+g[i].s[j];
		g[i].cnt=get_cnt(i);
	}
	sort(g+1,g+2+k,cmp);
	cout<<g[1].id<<endl;
	vector<pip>v;
	rep(i,2,k+2){
		if(g[i].cnt!=g[i-1].cnt) rep(j,1,n+1) rep(z,1,m+1) if(g[i-1].s[j][z]!=g[i].s[j][z]) v.push_back({1,{j,z}});
		v.push_back({2,{g[i].id,0}});
	}
	cout<<v.size()<<endl;
	for(auto it:v){
		pii t=it.se;
		if(it.fi==1) cout<<1<<" "<<t.fi<<" "<<t.se<<endl;
		else cout<<2<<" "<<t.fi<<endl;
	}
}
int main()
{
//	#ifndef ONLINE_JUDGE
//		freopen("title.in","r",stdin);
//		freopen("title.out","w",stdout);
//	#endif
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int _=1;
	//cin>>_; 
	while(_--){
		solve();
	}
	return 0;
}

G. Gaining Rating

题意:

t(1≤t≤10^4)组测试,每组给定长度为n的数组a,初始分数x,求涨到y最小需要多少次比赛。每一次都可以选一个ai,如果当前分数大于等于ai就会加一分,否则减一分。但ai不会变,必须平均的选择,即不能存在一个人比另一个人多打两次比赛。

思路:

从小到大排序,每一轮次都从小的开始选,然后就变成一道模拟题了。

首先看一下当前轮最多能打败多少个对手,假如能打败前i-1个,第i个x<a[i]了,如果还没有到y,后面的会先掉分。判断一下之后每一次到i分数的净增量为2*(i-1)-n,如果为负值就不可能超过y了,否则计算经过多少轮之后x>=a[i],然后继续判断。注意y有小于a[i]的情况。

因为i指针只会向后移动,所以复杂度为O(n)。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<list> 
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second 
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const int N=2e5+10;
LL a[N];
void solve()
{
	int n;
	LL x,y;
	cin>>n>>x>>y;
	rep(i,1,n+1) cin>>a[i];
	sort(a+1,a+n+1);
	LL cnt=0;
	int i=1;
	while(1){
		while(i<=n&&x>=a[i]){
			++i,++x,++cnt;
			if(x==y){
				cout<<cnt<<endl;
				return;
			}
		}
		if(i==n+1){
			cout<<cnt+y-x<<endl;
			return;
		}
		if(n-i+1>=i-1){
			cout<<-1<<endl;
			return;
		}
		if(y<=a[i]){
			LL len=2*(i-1)-n,d=y-x;
			LL tm=d/len;
			cnt+=tm*n;
			if(d%len==0) cout<<cnt<<endl;
			else cout<<cnt+d-tm*len+2*(n-i+1)<<endl;
			return;
		}
		LL len=2*(i-1)-n,d=a[i]-x;
		LL tm=d/len;
		if(d%len) ++tm;
		x+=tm*len,cnt+=n*tm;
		if(x>=y){
			cnt-=x-y;
			cout<<cnt<<endl;
			return;
		}
	}
}
int main()
{
	#ifndef ONLINE_JUDGE
		freopen("title.in","r",stdin);
		freopen("title.out","w",stdout);
	#endif
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int _=1;
	cin>>_; 
	while(_--){
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值