环形粒子加速器的能量校准
题意
给定一个长度为 的整数序列,它满足"循环单调非递减"性质:在环形意义下,至多存在一个断点位置
,使得
(下标取模),其余相邻对都满足
。
现在要把一个新能量值 插入序列,使得新序列仍然满足这个性质。如果有多个合法位置,选下标最小的。
思路
先搞清楚"循环单调非递减"到底是什么。你可以把序列想象成一个环,沿着环走一圈,最多只能有一个地方是"下降"的。比如 [23, 37, 39, 49, 49, 16, 22],从 49 到 16 有一个下降,其他都是非递减的——这就像一个排好序的数组被旋转了一下。
那插入 之后会发生什么?关键观察是:插入操作只影响局部。
假设我们把 插到位置
(0-indexed),新序列变成
。这个操作:
- 断开了原来
和
之间的相邻关系
- 新增了
和
这两对相邻关系
所以新序列的断点数 = 原来的断点数 - 被断开的那对是否是断点 + 新增的两对中有几个是断点。
用公式写就是:
$$
(边界情况: 或
时断开的是环形边
。而且这两个位置断开的是同一条边,所以
和
的断点数算出来一样,我们只需要考虑
就行。)
只要 就合法。从
开始扫到
,第一个合法的就是答案。
复杂度
- 预处理断点数:
- 枚举插入位置:
- 总体
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d",&n);
vector<int> e(n);
for(int i=0;i<n;i++) scanf("%d",&e[i]);
int x;
scanf("%d",&x);
if(n==0){
printf("%d\n",x);
return 0;
}
int bpCount = 0;
for(int i=0;i<n;i++){
if(e[i] > e[(i+1)%n]) bpCount++;
}
int best = -1;
for(int p=0; p<=n; p++){
int lv, rv, rem;
if(p==0 || p==n){
lv = e[n-1]; rv = e[0];
rem = (e[n-1]>e[0]) ? 1 : 0;
} else {
lv = e[p-1]; rv = e[p];
rem = (e[p-1]>e[p]) ? 1 : 0;
}
int nb = bpCount - rem + (lv>x?1:0) + (x>rv?1:0);
if(nb <= 1){ best = p; break; }
}
for(int i=0;i<best;i++){
if(i) printf(" ");
printf("%d",e[i]);
}
if(best>0) printf(" ");
printf("%d",x);
for(int i=best;i<n;i++) printf(" %d",e[i]);
printf("\n");
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] e = new int[n];
for (int i = 0; i < n; i++) e[i] = sc.nextInt();
int x = sc.nextInt();
if (n == 0) {
System.out.println(x);
return;
}
int bpCount = 0;
for (int i = 0; i < n; i++) {
if (e[i] > e[(i + 1) % n]) bpCount++;
}
int best = -1;
for (int p = 0; p <= n; p++) {
int lv, rv, rem;
if (p == 0 || p == n) {
lv = e[n - 1]; rv = e[0];
rem = (e[n - 1] > e[0]) ? 1 : 0;
} else {
lv = e[p - 1]; rv = e[p];
rem = (e[p - 1] > e[p]) ? 1 : 0;
}
int nb = bpCount - rem + (lv > x ? 1 : 0) + (x > rv ? 1 : 0);
if (nb <= 1) { best = p; break; }
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < best; i++) {
if (i > 0) sb.append(' ');
sb.append(e[i]);
}
if (best > 0) sb.append(' ');
sb.append(x);
for (int i = best; i < n; i++) sb.append(' ').append(e[i]);
System.out.println(sb);
}
}
import sys
input = sys.stdin.readline
n = int(input())
e = list(map(int, input().split()))
x = int(input())
if n == 0:
print(x)
else:
bp_count = sum(1 for i in range(n) if e[i] > e[(i+1) % n])
best = -1
for p in range(n + 1):
if p == 0 or p == n:
lv, rv = e[n-1], e[0]
rem = 1 if e[n-1] > e[0] else 0
else:
lv, rv = e[p-1], e[p]
rem = 1 if e[p-1] > e[p] else 0
nb = bp_count - rem + (1 if lv > x else 0) + (1 if x > rv else 0)
if nb <= 1:
best = p
break
result = e[:best] + [x] + e[best:]
print(' '.join(map(str, result)))
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line.trim()));
rl.on('close', () => {
const n = parseInt(lines[0]);
const e = lines[1].split(' ').map(Number);
const x = parseInt(lines[2]);
if (n === 0) {
console.log(x);
return;
}
let bpCount = 0;
for (let i = 0; i < n; i++) {
if (e[i] > e[(i + 1) % n]) bpCount++;
}
let best = -1;
for (let p = 0; p <= n; p++) {
let lv, rv, rem;
if (p === 0 || p === n) {
lv = e[n - 1]; rv = e[0];
rem = (e[n - 1] > e[0]) ? 1 : 0;
} else {
lv = e[p - 1]; rv = e[p];
rem = (e[p - 1] > e[p]) ? 1 : 0;
}
const nb = bpCount - rem + (lv > x ? 1 : 0) + (x > rv ? 1 : 0);
if (nb <= 1) { best = p; break; }
}
const result = [...e.slice(0, best), x, ...e.slice(best)];
console.log(result.join(' '));
});

京公网安备 11010502036488号