首页 > 其他分享 >ABC267G Increasing K Times 题解

ABC267G Increasing K Times 题解

时间:2023-04-25 18:25:31浏览次数:38  
标签:ABC267G int 题解 sum 个数 same Increasing 上坡 998244353

做这道题,很有感悟,发篇文。

先给数列从小到大排个序。

接下来设 \(f_{i,j}\) 表示前 \(i\) 个数的排列形成 \(j\) 个上坡的方案数。

接下来考虑转移,分为插入第 \(i\) 个数后增加上坡和不增加上坡两种情况。

对于不增加的情况,有三种可能:

  • 第 \(i\) 个数插入在了数列的最前端,有 \(1\) 种方案。
  • 第 \(i\) 个数插入在了一个上坡的中间,因为上坡中较小的那个数字必定小于第 \(i\) 个数,形成一个上坡,较大的那个数字必定小于等于第 \(i\) 个数,不形成上坡,而我们拆散了一个上坡,故没有增加,有 \(j\) 种方案。
  • 第 \(i\) 个数插入在了数值相同的数后面,这个记为 \(same_i\),有 \(same_i\) 种方案。

对于增加的情况,就是减去这三种情况了,不过增加了,就说明原来只有 \(j-1\) 个上坡,这里和上面不太一样。

整理式子,得:

\[f_{i,j} = f_{i-1,j-1} \times (i - j - same_i) + f_{i-1,j} \times (1 + j + same_i) \]

这样就可以 \(O(n^2)\) 求得了,可以用滚动数组。

#include <bits/stdc++.h>
using namespace std;
long long n, k, a[5005], f[5005], same[5005], sum;
int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; i++) {
        if (a[i] == a[i - 1])
            same[i] = same[i - 1] + 1;
    }
    f[0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = i - same[i]; j >= 1; j--) {
            f[j] = f[j - 1] * (i - j - same[i]) % 998244353 + f[j] * (1 + j + same[i]) % 998244353;
            f[j] %= 998244353;
        }
        f[0] = f[0] * (1 + same[i]) % 998244353;
    }
    cout << f[k] << endl;
}

After Increasing K Times

过了一段时间重新看了一下这道题,发现有几个优化,也顺便介绍一下。

首先,我们发现 \(n\) 很大,但是数值区间很小,所以考虑使用桶排序,因为数字在 \([1,n]\),所以排序复杂度为 \(O(n)\)。

然后,我们发现枚举区间可以缩小,因为我们并不是全都需要,简单用一个图表示:

左边是我们需要的值,右边是不需要的。

那么,有用的状态的区间边界很好推算,是 \([k+n-i+1,k]\),这个优化可以减少接近一半的时间。

以上优化让代码大大提速,获得了洛谷最优解,在 AtCoder 排名第二(截至2022.11.23)。

第一名本人丧心病狂卡常也卡不过,快了 4ms,但是本代码很短,最快代码使用了 IDFT。

#include <stdio.h>
inline int read() {
    char c = getchar();
    int sum = 0;
    while (c < '0' || c > '9') c = getchar();
    do {
        sum = (sum << 3) + (sum << 1) + c - '0';
        c = getchar();
    } while (c >= '0' && c <= '9');
    return sum ;
}
int n, k,s[5005],b[5005],t=1;
long long f[5005];
int main() {
    n=read(),k=read();
    for (int i = 1; i <= n; i++)b[read()]++;
    for(int i=1;i<=n&&t<=n;i++)
    {
    	if(b[i])b[i]--,t++;
    	while(b[i])b[i]--,s[t] = s[t - 1] + 1,t++;
	} 
    f[0] = 1;
    for (int i = 1; i <= n; i++) {
		int r=(k>i-s[i])?(i-s[i]):k,l=(k-n+i-1>1)?(k-n+i-1):1;
        for (int j = r; j >= l; j--) {
            f[j] = f[j] * (j + s[i] + 1) + f[j - 1] * (i - j - s[i]) ;
            f[j] %= 998244353;
        }
        f[0] = f[0] * (s[i] + 1) % 998244353;
    }
    printf("%lld\n",f[k]);
    return 0;
}

标签:ABC267G,int,题解,sum,个数,same,Increasing,上坡,998244353
From: https://www.cnblogs.com/I-am-joker/p/17353465.html

相关文章

  • 2021牛客OI赛前集训营-提高组(第二场)第三题 树数树题解
    题目描述牛牛有一棵\(n\)个点的有根树,根为\(1\)。我们称一个长度为\(m\)的序列\(a\)是好的,当且仅当:\(\foralli\in(1,m]\),\(a_i\)为\(a_{i−1}\)的祖先或\(a_{i−1}\)是\(ai\)的祖先\(\forall1\leqi\ltj\leqm,a_i\neqa_j\)你需要帮助牛牛求出最长的......
  • 2021牛客OI赛前集训营-提高组(第三场) 第二题 交替 题解与结论证明
    题目描述一个长度为\(n\)的数组\(A\),每秒都会变成一个长度为\(n−1\)新数组\(A'\),其变化规则如下:若当前数组\(A\)的长度\(n\)为偶数,则对于新数组\(A'\)的每一个位置\(i(1≤i<n)\)来说,\(A'[i]=A[i]+A[i+1]\)若当前数组\(A\)的长度\(n\)为奇数,则对于......
  • 【SD集训】20230425 T2 差(difference) 题解 CF1500F 【Cupboards Jumps】
    大家可以猜猜看为什么有两个标题,因为这个原因本文就不设密码了,被He_ren的原题创到了。吐槽一下,He_ren甚至出原题还用脚造数据,虽然数据确实比较难造。不过那两个\(O(n^2)\)老哥好像都没最后将所有数调整成非负,遗憾20。有人场切*3500却没过签到题,我不说是谁。题目描述......
  • Net6+axios 返回401 axios不能获取 状态码问题解决
    错误使用app.UseAuthentication();//认证 这里要加,位置不能反app.UseAuthorization();//授权 app.UseCors();//启用Cors解决方法app.UseCors();//启用Corsapp.UseAuthentication();//认证 这里要加,位置不能反app.UseAuthorization();//授权  更换前更换后  ......
  • 题解:【CTS2022】 独立集问题
    题目链接来自2023SDPT-Round1-Day4课上Qingyu的讲解。考虑对于一个点多次操作会发生什么?第一次操作会将周围的点的权值吸过来,自己对答案的贡献乘\(-1\),周围的点的贡献乘\(+1\),得到新的权值\(a_x'=\pma_x\mp\sum_{y\inson_x}a_y\);再一次操作,我们可以将这个新的贡......
  • Mount cifs存储时提示not supported问题解决
    Mountcifs存储时提示notsupported问题解决:报错: mounterror(95):Operationnotsupported排查:1、当时刚好是mount2个存储,结果1个可以1个不行,就反馈给负责存储同事查看2个存储的区别2、存储同事查看后得出不行的是比较老的Netapp存储,mounterror(95)错误应该是不支持的smb协议......
  • leetcode-217-存在重复元素 题解
    题目描述给你一个整数数组nums。如果任一值在数组中出现至少两次,返回true;如果数组中每个元素互不相同,返回false。示例1:输入:nums=[1,2,3,1]输出:true示例2:输入:nums=[1,2,3,4]输出:false示例3:输入:nums=[1,1,1,3,3,4,3,2,4,2]输出:true提......
  • P9228 原神 题解
    题目传送门题目大意有一个魔法师,她可以用火元素攻击魔法把对附着冰元素的怪物的伤害\(\times2\),用冰元素攻击魔法把对附着火元素的怪物的伤害\(+5\)。每个怪物初始时没有附着任何元素,给出冰、火元素对每个怪物的初始伤害,魔法师可以任意安排攻击顺序,求最大总伤害。解题思路......
  • CF题解
    E.RearrangeBrackets2100括号树gq!https://codeforces.com/contest/1821/problem/E题解:若我们把序列看作是一个由匹配括号组成的森林,外层括号是内层括号的父亲,则整个正则括号序列的cost可以看作是森林中所有点的深度之和,根节点深度为0,故每次操作可以看作是将某棵树的父节点......
  • 跨域问题解决、其他权限校验方法
    跨域问题解决浏览器出于安全的考虑,使用XMLHttpRequest对象发起HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。前后端分离项目前端项目和后端项目一般都不是同源的,所以肯定会存在......