首页 > 其他分享 >CF1852

CF1852

时间:2024-02-05 14:23:16浏览次数:24  
标签:数列 CF1852 位置 插入 ans sim inc

你谷的加题速度实在太慢了

被 CF 的题目薄纱

A

可以选任意次 \(i\in [1,n]\),使 \(a[1\sim i]++,a[i+1\sim n]--\)。求最少操作次数使得原数列变成非从小到大排序的。

首先判断原数列是否已经非排序。然后看每一个相邻位置 \(a[i],a[i+1]\),令 \(ans=\min(ans,(a[i+1]-a[i])\div2+1).\)

B

斐波那契式数列:\(a_i=a_{i-1}+a_{i-2}\),但 \(a_{1,2}\) 不定。每项非负。

有多少个斐波那契式数列满足第 \(k\) 项是 \(n\)。

Hint: Can a sequence involving \(n\), which is up to \(10^5\), really have up to \(10^9\) terms?

其实,根据斐波那契数列的增长速度,根本到达不了 \(10^9\) 的项数。我们枚举数列倒数第二项 \(1\sim n\),倒推 \(k\) 项,看看是否满足每一项都非负。

C

\(1\sim +\infty\),每次会删去这些数中的第 \(a_{1\sim n}\) 小的数。问:删除 \(k\) 次后,剩下的最小数是多少。

反向考虑。我们不是删除,而是在 \(a_i-i\) 个位置后面插入数。这样的好处是我们不用看我们删完之后谁接上来,只用在一个固定的位置不断插入即可。

记 \(res\) 为最终最小值,这只是我们记出来方便思考。初始令一变量 \(ans=1\),表示第 \(k\) 天后 \(res\) 的排名是 \(1\)。(最后答案前面的删完了自然是 \(1\))

考虑插入一些数回到前一天的状态,等回到第 \(1\) 天前,此时 \(ans\) 的值就是初始时 \(res\) 的位置,也就是要输出的答案。(先特判 \(a[1]\ne1\) 则答案必为 \(1\))

在所有 \(a_i-i\) 位置插入数,保证 \(a_i-i\le ans\),因为插入到 \(ans\) 位置后面没有意义。

注意我们并不在乎插入了什么数,只需统计每次在 \(ans\) 前又插入了几个数 \(cnt\),同时在这次结束时\(ans\leftarrow ans+cnt\) 即可

然后在更新了 \(ans\) 时,要注意又有一些 \(a_i-i\) 可以插入到 \(ans\) 前面了,同步更新。

解释一下 CF 官方代码。

#include <bits/stdc++.h>
using namespace std;

int n, k, a[200010];

void solve() {
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        a[i] -= i; //是在a[i]-i位置插入,而非a[i]
    }
    if (a[0] != 1) { //特判
        cout << 1 << "\n";
        return;
    }
    a[n] = 2e9; //边界守卫
    long long ans = 1; //答案
    int inc = 1; //inc表示本次插入会在ans前插入多少个
    while (inc < n) {
        int days = (a[inc] - ans + inc - 1) / inc;
        //插入1次不能让下一个a[i]-i排到ans前
        //一次性加很多次,跳到下一个a[i]-i也排前,优化
        if (days >= k){
            //如果要下一个a[i]-i排前
            //已经超过剩余插入次数,就结束
            ans += k * inc;
            //那还能插入(剩余次数)*(插入个数)个
            k = 0;
            break;
        }
        ans += days * inc;
        //插入了(插入次数)*(多少个插入位置在ans前)
        k -= days;//减少剩余插入次数
        while (a[inc] <= ans) inc++;
        //拓展在ans前的个数
    }
    ans += 1ll * k * n;
    //1.上面没等到inc>=n就没有了剩余次数,k=0无影响
    //2.inc=n出来的,剩下k次每次都插入n个
    cout << ans << "\n";//输出
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while (t--)
    	solve();
}

D

定义长度 \(n\) 的“不平衡数组” \(\{b_n\}\):

  1. \(-n\le b_i\le n.\)

  2. \(\forall i,j,b_i+b_j\ne 0.\)

  3. 恰有 \(a_i\) 个位置 \(j\),使 \(b_i+b_j>0\),允许 \(i=j\).

现给定 \(\{a_n\}\)。要么指出不存在 \(\{b_n\}\),要么构造出一组 \(\{b_n\}\)。

提示:

\((n,-n),(n-1,-(n-1)),\dots,(1,-1)\)。
每对里只能选一种。

\(b_i>b_j\iff a_i>a_j.\)

设 \(x\) 是使 \(|b_i|\) 最大的 \(i\)。若 \(b_x<0\),则 \(a_x=0\);否则 \(a_x=n\)。同时,不可能有另一个 \(a_y=0\) 或 \(n\)。

所以“存在绝对值最大的 \(|b_i|\)” $\iff $

“\((\)存在一个 \(a_i=0)\)”\(\bigoplus\) “存在一个 \(a_i=n\)”。

先判断是否存在绝对值最大,然后固定此位置为绝对值最大,就可以递归处理剩余没处理的数!!!

如果在某次递归中不存在绝对值最大,说明答案不存在。

但是每次循环找 \(a_i=0/n\) 是 \(O(n^2)\) 的。我们可以将 \(a_i\) 排序。这样每次判断就是 \(O(1)\) 的了!

标签:数列,CF1852,位置,插入,ans,sim,inc
From: https://www.cnblogs.com/FLY-lai/p/18007890

相关文章

  • CF1852B Imbalanced Arrays 题解
    CF1852BImbalancedArrays题解Links洛谷CodeforcesDescription对于一个给定的长度为\(n\)的数组\(A\),定义一个长度为\(n\)的数组\(B\)是不平衡的当且仅当以下全部条件满足:\(-n\leqB_{i}\leqn\)且\(B_{i}\ne0\)。即每个数在\([-n,n]\)内且不为\(0\)。......
  • CF1852C Ina of the Mountain
    *2400https://codeforces.com/problemset/problem/1852/C如果没有\(\modk\)的限制的话,我们都会做,因为都是正数,那么\(\sum_i^nd_i>0\),因此,答案即为\(\sum[d_i>0]d_i\)。但是现在多了一个操作,即为区间加\(k\),那么转到差分数组就是\(d_l+k,d_r-k\),且该操作不花费。观察,差......
  • 【题解】CF1852C Ina of the Mountain
    我们先从题目的一部分入手。如果说,我们没有当一个数为\(0\)时,让这个数变成\(k\)的性质,我们如何求答案呢?很简单,在图上就是:绿色线段的长度加起来即为答案(本图中是\(6\))我们考虑很显然地,将一个数从\(0\)变为\(k\)即为将一个数一开始加上\(k\)我们如果要让第\(i\)列......
  • CF1852A Ntarsis' Set
    题目大意集合\(S:1,2,3,4,\dots,10^{1000}\)。给定长度为\(n\)的单调递增正整数序列,给定一个数\(k\)。对\(S\)进行\(k\)次删除操作,每次以序列为下标删除最小元素,即每次同时删除集合中第\(a_1,a_2,\dots,a_n\)小的元素。求\(k\)次删除操作后\(S\)中最小元素。思......
  • 题解 Codeforces Round 887 (Div 1+Div 2) / CF1853AB,CF1852ABCD
    下大分!悲!Div1只过了1A!!!但还是补完整场Div2吧。A.Desortinghttps://codeforces.com/problemset/problem/1853/Aproblem用操作:\([1,i]++,[i+1,n]--\),使得数组不单调不降,求最小操作次数。\(n\leq10^5\)。solution操作等同于在差分数组上选出\(i\),做\(c_1:=c_1+1,c_i:......