打卡信奥刷题(3514)用C++实现信奥题 P10883 [COCI 2017/2018 #2] Doktor

P10883 [COCI 2017/2018 #2] Doktor

题目描述

夫人说:

「我已经骑马十五年了,不可能把马倒着钉蹄铁!」

(……)

「是的,那是倒着的。」——多马戈伊低声说道,看着马特的手,正在玩一个经过大幅修改的纸牌游戏 Hanabi。为了简单起见,马特手中有 NNN 张牌,按顺序编号为 1,2,…,N1, 2, \dots, N1,2,,N
每个数字从 111NNN 恰好出现一次。就像玩真正的游戏一样,他不能主动改变牌的顺序。

为了让任务至少与故事有些关联,多马戈伊会指向马特手中一段连续的牌子序列。(他也可以指向单张牌,但至少会指向一张牌。)然后马特将「旋转」该连续子数组并放回去。

(旋转可以被认为是将给定子数组中的所有牌旋转 180 度。这意味着第一张和最后一张牌交换位置,第二张和倒数第二张牌交换位置,依此类推。)

和我们所有人一样,多马戈伊非常喜欢不动点。换句话说,就是牌的数字与它们在手中的位置相匹配的牌,从多马戈伊的左侧开始计数。因此,他希望在旋转给定子数组后,不动点的数量尽可能多。

帮助多马戈伊找出他需要指出哪一段连续子数组,以便在旋转该子数组后,马特手中的不动点数量达到最大。

输入格式

输入的第一行包含正整数 N(1≤N≤500000)N (1 \leq N \leq 500000)N(1N500000),表示马特手中的牌数。

接下来的行包含多马戈伊看到的马特手中牌的顺序。

输出格式

你必须输出一行,包含 AAABBB,即所需连续子数组的起始和结束牌上的数字,按此顺序。如果有多个选项,输出其中任意一个。

输入输出样例 #1

输入 #1

4
3 2 1 4

输出 #1

3 1

输入输出样例 #2

输入 #2

2
1 2

输出 #2

1 1

输入输出样例 #3

输入 #3

7
3 6 5 7 4 1 2 

输出 #3

3 2

说明/提示

在第一个测试用例中,旋转从 3 开始到 1 结束的连续子数组后,牌的顺序将变为 1 2 3 4,现在所有的牌都是不动点。在这个例子中,给定的输出是唯一正确的输出。

在第二个测试用例中,旋转任何仅包含一张牌的子数组会导致相同的牌顺序,这种顺序产生最大数量的不动点。(由 ChatGPT 4o 翻译)

C++实现

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+100;
int n,a[maxn+100],b[maxn+100],c[maxn+100],ans=0,ans1=1,ans2=1;
vector<int> vec[(maxn<<1)+100];
bool cmp(int a,int b){return a>b;}

int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin >> n;
	for(int i = 1;i <= n;i++) cin >> a[i];
	for(int i = 1;i <= n;i++){
		b[i] += b[i-1];
		if(a[i] == i) 
			b[i]++;
		vec[a[i]+i].push_back(min(a[i],i));		
	}
	for(int i = 1;i <= 2*n;i++){
		if(vec[i].size() == 0) continue;
		sort(vec[i].begin(),vec[i].end(),cmp);
		for(int j = 0;j < vec[i].size();j++){
			int lpos = vec[i][j];
			if(j+1+b[lpos-1]-b[i-lpos] > ans){
				ans = j+1+b[lpos-1]-b[i-lpos];
				ans1 = a[lpos];
				ans2 = a[i-lpos];
			}
		}
	}
	if(ans == 0) 
		cout << 1 << " " << 1 << '\n';
	else 
		cout << ans1 << " " << ans2 << '\n';
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值