专栏文章
题解:P14131 【MX-X22-T2】「TPOI-4B」K Problem
P14131题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @minq1e78
- 此快照首次捕获于
- 2025/12/02 06:29 3 个月前
- 此快照最后确认于
- 2025/12/02 06:29 3 个月前
这是一个 的瞎搞做法。
我们称一个区间是合法的当且仅当期间有 个 , 个 , ... , 个 。
观察到我们所求的合法区间长为 ,因此可以考虑枚举所有长为 的区间,然后使用桶维护该区间内的各个元素之数量以判断其是否合法,时间复杂度为 ,显然无法通过。
因此我们考虑优化,观察到长度为 的合法区间,其元素和必须等于 。因此,我们预处理前缀和数组,仅对长度和区间和均符合上述条件的区间进行合法性检验。尽管时间复杂度仍为 ,但常数贼小,能够通过本题:
CPP#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100050;
long long a[MAXN], s[MAXN], d[MAXN];
int ans = 0;
void check(int a1, int b, int c){ // 判断长为 c(c+1)/2 的区间 [a,b] 是否合法,如果是便更新答案,否则不动
for(int i = 1; i <= c; i ++) d[i] = 0;
for(int i = a1; i <= b; i ++){
d[a[i]] ++;
}
for(int i = 1; i <= c; i ++){
if(d[i] != i) return;
}
ans = c;
}
void solve(){
int n = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) s[i] = 0;
for(int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
s[i] = s[i - 1] + a[i];
}
ans = 0;
for(int l = 1; l * (l + 1) <= 2 * n; l ++){
int length = (l * (l + 1)) / 2;
for(int i = 1; i + length <= n; i ++){
int sum = l * (l + 1) * (2 * l + 1);
if(s[i + length - 1] - s[i - 1] == sum / 6) check(i, i + length - 1, l);
if(ans == l) break; // 此时继续往后枚举不影响答案,break掉即可
}
}
printf("%d\n", ans);
}
int main(){
int t = 0;
scanf("%d", &t);
for(int i = 1; i <= t; i ++){
solve();
}
}
当然,如果出题人刻意构造数据卡掉该做法,我们还能更新换代:考虑再维护一个前缀和数组来计算数组 每一项的平方和,此后在调用
check 函数前增加判断该区间的平方和是否为 。这样,程序每次使用 check 函数几乎都能找到合法区间,虽然时间复杂度仍为 ,但能够通过且较难卡掉。相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...