P10883 [COCI 2017/2018 #2] Doktor
题目描述
夫人说:
「我已经骑马十五年了,不可能把马倒着钉蹄铁!」
(……)
「是的,那是倒着的。」——多马戈伊低声说道,看着马特的手,正在玩一个经过大幅修改的纸牌游戏 Hanabi。为了简单起见,马特手中有 NNN 张牌,按顺序编号为 1,2,…,N1, 2, \dots, N1,2,…,N。
每个数字从 111 到 NNN 恰好出现一次。就像玩真正的游戏一样,他不能主动改变牌的顺序。
为了让任务至少与故事有些关联,多马戈伊会指向马特手中一段连续的牌子序列。(他也可以指向单张牌,但至少会指向一张牌。)然后马特将「旋转」该连续子数组并放回去。
(旋转可以被认为是将给定子数组中的所有牌旋转 180 度。这意味着第一张和最后一张牌交换位置,第二张和倒数第二张牌交换位置,依此类推。)
和我们所有人一样,多马戈伊非常喜欢不动点。换句话说,就是牌的数字与它们在手中的位置相匹配的牌,从多马戈伊的左侧开始计数。因此,他希望在旋转给定子数组后,不动点的数量尽可能多。
帮助多马戈伊找出他需要指出哪一段连续子数组,以便在旋转该子数组后,马特手中的不动点数量达到最大。
输入格式
输入的第一行包含正整数 N(1≤N≤500000)N (1 \leq N \leq 500000)N(1≤N≤500000),表示马特手中的牌数。
接下来的行包含多马戈伊看到的马特手中牌的顺序。
输出格式
你必须输出一行,包含 AAA 和 BBB,即所需连续子数组的起始和结束牌上的数字,按此顺序。如果有多个选项,输出其中任意一个。
输入输出样例 #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考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容
用C++实现信奥题 P10883 COCI 20172018 #2 Doktor&spm=1001.2101.3001.5002&articleId=163812168&d=1&t=3&u=3ebe467e600a42828c3bf25cf88709ad)
257

被折叠的 条评论
为什么被折叠?



