首页 > 其他分享 >Codeforces 1661F Teleporters

Codeforces 1661F Teleporters

时间:2024-02-18 20:13:45浏览次数:27  
标签:Teleporters cnt 1661F sum Codeforces 贡献 i64 操作 贪心

先考虑贪心,令 \(f(x, k)\) 为满足 \(\sum\limits_{i = 1}^k s_i = x, s_i\in \mathbb{N}_+\) 的 \(s\) 的 \(\sum\limits_{i = 1}^k s_i^2\) 的最小值。
也就是题目中在两个固定的点中放 \(k - 1\) 个点这两个点中的最小贡献。
平均分肯定是最优的,可以通过 \(x\bmod k\) 的值 \(O(1)\) 算出 \(f(x, k)\)。

那么就可以考虑令当前两个点中的一段已经分了 \(k\) 段了(初始就是分了 \(1\) 段),贡献为 \(f(x, k)\)。
如果花费 \(1\) 的代价,会分成 \(k + 1\) 段,贡献为 \(f(x, k + 1)\)。
显然会去选择 \(f(x, k) - f(x, k + 1)\) 最大的一个,因为代价相同,贡献肯定越少越好,且能发现 \(f(x, k) - f(x, k + 1)\) 随着 \(k\) 的增长而减少,选这个肯定不会比还没有选到的操作劣。

直接贪心可能会因为极小的 \(m\) 导致贪心次数过多而 \(\text{T}\) 掉。

考虑到令 \(g(i)\) 为代价为 \(i\) 时最小的贡献。
根据上面的贪心,能知道每次选的肯定都是没选的之中最优的,也就是贡献减少的最多的。
于是可以得到 \(g(i - 1) - g(i)\le g(i - 2) - g(i - 1)\),即第 \(i\) 次花费 \(1\) 代价减少的贡献肯定不会超过第 \(i - 1\) 次减少的贡献。

于是就可以考虑通过二分 \(g(i - 1) - g(i)\) 的值 \(x\),并只操作减少的贡献 \(\ge x\) 的操作。
可以根据最后的结果 \(sum\) 和选出的个数 \(cnt\) 判断 \(sum\) 与 \(m\) 的大小关系根据 \(cnt\) 得到答案。
注意可能有多个减少的贡献 \(= x\) 的操作,在最后得到的 \(sum\) 是这些操作都用了的值,但如果能少用几个操作使得 \(sum\) 依然 \(\le m\) 那就可以撤销这几次操作。
这种方法的另一种解释就是考虑考虑 \((i, g(i))\) 组成了一个下凸壳,二分斜率看切点 \(u\) 的 \(g(u)\) 是否 \(\le m\)。

对于找到减少贡献 \(\ge x\) 的操作,可以通过二分得到。

注意特判不进行操作就已经满足条件的情况。

时间复杂度 \(O(n\log n\log V^2)\),\(V\) 是 \(a_i\) 的值域。

#include<bits/stdc++.h>
using i64 = long long;
inline i64 f(i64 x, i64 k) {
    if (x % k == 0) return x / k * x;
    i64 c1 = x % k, c2 = k - c1;
    return (x / k) * (x / k) * c2 + (x / k + 1) * (x / k + 1) * c1; 
}
const int maxn = 2e5 + 10;
int n; i64 m;
i64 a[maxn];
i64 sum, cnt;
void solve(i64 w) {
    sum = cnt = 0;
    for (int i = 1; i <= n; i++) {
        i64 l = 2, r = a[i], t = 1;
        while (l <= r) {
            i64 mid = (l + r) >> 1;
            f(a[i], mid) - f(a[i], mid - 1) - w <= 0 ? (t = mid, l = mid + 1) : (r = mid - 1);
        }
        sum += f(a[i], t), cnt += t - 1;
    }
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    for (int i = n; i; i--) a[i] -= a[i - 1];
    i64 l = 0;
    for (int i = 1; i <= n; i++) l = std::max(l, a[i]);
    l *= l, l *= -1;
    scanf("%lld", &m);
    solve(l);
    if (sum <= m) return puts("0"), 0;
    i64 r = -1, ans = m;
    while (l <= r) {
        i64 mid = (l + r) >> 1;
        solve(mid);
        sum <= m ? (ans = cnt - (sum - m) / mid, r = mid - 1) : (l = mid + 1);
    }
    printf("%lld\n", ans);
    return 0;
}

标签:Teleporters,cnt,1661F,sum,Codeforces,贡献,i64,操作,贪心
From: https://www.cnblogs.com/rizynvu/p/18019879

相关文章

  • Codeforces Round 903 (Div. 3)
    题目链接A.按题意模拟字符串find函数if(x.find(s)==string::npos)//没找到#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;#defineinf0x3f3f3f3fvoidsolve(){intn,m;cin>>n>>m;stringx,s;cin>>x&g......
  • CF1929 Codeforces Round 926 (Div. 2)
    C.SashaandtheCasino当\(k<x\)时,显然我们只需要每次下注一个硬币就好了.当\(k>x\)时.考虑先一个一个的下硬币,那么为了保证不亏本,最多输\(k-2\)局,然后在第\(k-1\)局赢,这样才能盈利\(1\)个硬币.那么在第\(k\)局之后呢?此时我们最少也需要下注两个硬币,这......
  • Codeforces Round 922 (Div. 2)
    A.BrickWall因为水平砖块的长度至少为\(2\),所以一行中水平砖块最多放\(\lfloor\frac{m}{2}\rfloor\)块,因此答案不超过\(n\cdot\lfloor\frac{m}{2}\rfloor\)。如果\(m\)是奇数,用长度为\(\lfloor\frac{m}{2}\rfloor\)的水平砖块平铺过去,最后一块长度为\(3\),这样......
  • Codeforces 解题报告(202402)
    CodeforcesRound926D-SashaandaWalkintheCitydp,主要难点在于设状态。发现子树内一旦存在一个点,到当前子树的根节点路径上有两个危险点,那么除了那条链所属的子树,其他的点就都不能选了。所以把这个性质放进状态,设\(f_{u,0/1}\)表示以\(u\)为根的子树内,是否存在一......
  • Codeforces(1500板刷)
    目录写在前面1.A.DidWeGetEverythingCovered?(构造、思维)题目链接题意题解代码总结2F.Greetings(离散化+树状数组)题目链接题意题解代码总结写在前面开始板刷1500了,主要是最近卡1300-1400上不去,发现cf很多思维题要不是想不到,要不就是签的慢,被读题卡了心态就巨难受,一下就......
  • Codeforces Round 926 (Div. 2) 总结
    A题意:给出一个数组,让你重新排序,\(\sum_{i=1}^{n-1}a_i-a_{i+1}\)最大。做法:显然从小到大排序即可,答案就是最大值减去最小值。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=1e6+5,MOD=998244353;signedmain(){ios::sync_with_s......
  • Codeforces Round 926 (Div. 2) DEF
    D.SashaandaWalkintheCity题意:给定一棵树,问不存在三个点属于同一条路径的点集个数。\(f[x]\)表示,最近公共祖先为\(x\)的合法非空集数量。如果选\(x\),那么只能为不选子树或选一棵子树,否则\(u\insubtree[y_1]\),\(v\insubtree[y_2]\)与\(x\)共链。?贡献为\(......
  • Codeforces Round 926 (Div. 2) 赛后总结
    这场比赛掉了前三场比赛上的分,望周知。SashaandtheBeautifulArray题目大意:一个有n个数的数组,对n个数进行排序,求数组中ai-ai-1(下标从2到n)的和的最大值。分析列出来和式,为an-an-1+an-1-an-2……-a1最后得到an-a1那么an最大,a1最小即可。很容易想到排序。#include<i......
  • Codeforces Round 926 (Div. 2)(A~D)
    目录ABCDA输出最大值减最小值,或者排序算一下答案#include<bits/stdc++.h>#defineintlonglong#definerep(i,a,b)for(inti=(a);i<=(b);++i)#definefep(i,a,b)for(inti=(a);i>=(b);--i)#definepiipair<int,int>#definelllonglong#definedb......
  • Codeforces Round 926 (Div. 2) 题解
    比赛链接:https://codeforces.com/contest/1929官解链接:https://codeforces.com/blog/entry/125943出的很差的一场。推歌CF1929A.SashaandtheBeautifulArray题意任意排列数组\(a_{1..n}\),求\(\sum_{i=2}^n(a_i-a_{i-1})\)的最大值。题解见过最显然的A题,奠定了......