[PA2020] Punkty rankingowe 解题记录
题意简述
给定一个长度为
n
n
n 的序列
a
a
a,其中
a
i
a_i
ai 表示一个序列中连续
i
i
i 个元素的最大值,求这个序列,可能有多种解。如果有解,输出任意一种;否则输出 NIE
。
题目分析
看到这种有 Special Judge
的题目首先就得想到构造。
我们假设所有情况都是有解的,那么对于一个序列 b b b,我们可以假设 b b b 的前 i i i 项的和就是连续 i i i 项的最大值,也就是题目所给的 a i a_i ai,那么这个构造柿子就显而易见了。
因为 b b b 的前 i i i 项的和是 a i a_i ai,并且此时 b b b 中只有 i i i 个数,所以对于连续 i + 1 i+1 i+1 个数的最大值,我们只能添加一个数,使得前 i + 1 i+1 i+1 项的和为 a i + 1 a_{i+1} ai+1,这个数显然就是 a i + 1 − ∑ j = 1 i b j a_{i+1}-\sum\limits_{j=1}^{i}b_j ai+1−j=1∑ibj。也就是 b i = a i − a i − 1 b_i=a_i-a_{i-1} bi=ai−ai−1。
接下来我们再来考虑不合法的情况。
因为我们表示的 ∑ j = 1 i b j \sum\limits_{j=1}^{i}b_j j=1∑ibj 是连续 i i i 项的和,那么如果在更新到第 i + 1 i+1 i+1 项的时候,在这 i + 1 i+1 i+1 项中有连续的 j ∈ [ 1 , i ] j \in [1,i] j∈[1,i] 项的最大值大于了 a i a_i ai 那么就不合法。例如下面这组数据:
5
3 1 4 1 5
当我们按照上面的构造柿子构造到最后一项时, b b b 数组为:
3 -2 3 -3 4
可以发现最后四项的和为 2 2 2,大于题目给的 a 4 = 1 a_4=1 a4=1,故不符合条件。
区间和用前缀和统计即可。
AC Code
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
CI N=1e5+5;
int n,a[N],b[N],s[N];
signed main() {
std::cin>>n;
arrin(a,n);
rep(i,1,n){
b[i]=a[i]-a[i-1];
s[i]=s[i-1]+b[i];
rep(len,1,i){
rep(l,1,i-len+1){
int r=l+len-1;
if(s[r]-s[l-1]>a[len]){
puts("NIE");
exit(0);
}
}
}
}
puts("TAK");
std::cout<<n<<"\n";
arrout(b,n);
return 0;
}