CF2090

CF2090D Simple Permutation

Bertrand–Chebyshev theorem:对 \(\forall n > 1\)\((n, 2n]\) 中至少存在一个素数。
这是定量刻画“在任意大区间内必有素数”的一个初等定理。

考虑以此构造,题目的这个 \(\lfloor \frac{n}{3} \rfloor\) 给了我们一些提示。我们考虑在 \([\lfloor \frac{n}{3} \rfloor, \lceil \frac{2n}{3} \rceil]\) 中找到一个质数 \(p\)。然后以 \(p, p - 1, p + 1, p - 2, p + 2 \cdots\) 进行构造,可以发现,这至少可以进行 \(\lfloor \frac{n}{3} \rfloor\) 轮。后面的数就随便填了。

Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
bool check(int x){
    if(x == 1) return 0;
    for(int i = 2; i <= x / i; ++i)
        if(x % i == 0) return 0;
    return 1;
}
void solve(){
    int n; cin >> n;
    if(n == 2){
        cout << 1 << ' ' << 2 << '\n';
        return;
    }
    int l = n / 3, r = (2 * n + 2) / 3, p;
    for(int i = l; i <= r; ++i){
        if(check(i)){
            p = i;
            break;
        }
    }
    cout << p << ' ';
    int k = min(p, n - p + 1);
    for(int i = 1; i < k; ++i) cout << p - i << ' ' << p + i << ' ';
    for(int i = p - k; i >= 1; --i) cout << i << ' ';
    for(int i = p + k; i <= n; ++i) cout << i << ' ';
    cout << '\n';
}
int main(){
    cin.tie(nullptr)->sync_with_stdio(0);
    int T; cin >> T;
    while(T--) solve();
    return 0;
}

CF2090E Canteen

先断环为链。
首先 \(a\) 右旋等价于 \(b\) 左旋。
\(k = 0\) 是容易的。我们令 \(c_i = b_i - a_i\),发现如果当 \(c_i < 0\) 时,实际上需要右边的来补它,直到它大于 0,也就是找到第一个 \(sum_r - sum_i + c_i = sum_r - sum_{i - 1} \ge 0\)。答案是 \(\max(r - i)\)。可以用单调栈/二分实现。
\(k \ge 0\) 时,考虑二分答案 \(x\)。这意味着对于所有 \(i\)\([i, i + x - 1]\) 中至少有一个 \(sum\) 大于等于 \(sum_{i - 1}\)。如果不满足我们就调整 \(c_i\)。但问题是由于是一个环,我们可能调整了前面的某个 \(c_i\),然后让后面的不用再调整了。所以我们找到 \(sum\) 最大的那个位置 \(p\),让 \(p\) 作为序列的末端(实际上是我们求解答案的开始),这样最后的 \(x\) 个数一定都满足,无需调整。而对于更前面的,也就不存在环的问题了。然后求定长区间最大值,滑动窗口即可。
这个消除后效性的办法可以稍微注意一下。

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 5;
ll q[N], a[N], b[N], c[N], n, k, sum[N], sm, p, tg, ori[N];
bool check(int x){
    int l = 1, r = 0;
    q[++r] = p + n;
    tg = 0;
    for(int i = p + 1; i <= p + n; ++i) sum[i] = ori[i];
    for(int i = p + n - 1; i >= p + 1; --i){
        if(q[l] >= i + x) ++l;
        while(l <= r && sum[q[r]] + tg <= sum[i]) --r;
        q[++r] = i, sum[i] -= tg;
        ll mx = sum[q[l]] + tg;
        // cout << i << ' ' << i + x - 1 << ' ' << mx << '\n';
        if(mx < sum[i - 1]) tg += sum[i - 1] - mx; 
    }
    return tg <= k;  
}
void solve(){
    cin >> n >> k;
    sm = 0;
    for(int i = 1; i <= n; ++i) cin >> a[i], sm += a[i];
    for(int i = 1; i <= n; ++i) cin >> b[i];
    for(int i = 1; i <= 2 * n; ++i){
        if(i <= n) c[i] = b[i] - a[i];
        else c[i] = c[i - n];
        sum[i] = sum[i - 1] + c[i];
        ori[i] = sum[i];
    }
    if(k >= sm) return cout << 0 << '\n', void();
    p = 0;
    for(int i = 1; i <= n; ++i){
        if(sum[i] > sum[p]) p = i;
    }
    // cout << p << '\n';
    int l = 1, r = n;
    while(l < r){
        int mid = (l + r) >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    cout << l << '\n';
} 
int main(){
    cin.tie(nullptr)->sync_with_stdio(0);
    int T; cin >> T;
    while(T--) solve();
    return 0;
}
posted @ 2025-11-12 11:49  Hengsber  阅读(7)  评论(0)    收藏  举报