【做题笔记】CF1659D Reverse Sort Sum
Problem
题目大意:
有一个长度为 \(n\) 的 \(01\) 序列 \(a\)。定义 \(b_{i,j}\) 为将 \(a\) 的 \(1\) 到 \(j\) 排序后第 \(a_i\) 的值。定义 \(c_i=\sum\limits_{j=1}^n b_{i,j}\)。现在给你序列 \(c\),求一个合法的 \(a\)。
Solution
首先 \(c\) 中最前面若干个 \(0\) 的位置显然有 \(a_i=0\)。
\(c\) 中第一个非 \(0\) 的位置必然有 \(a_i=1\)。
考虑这之后的数。
首先容易发现,对于每个序列 \(b_{i,j}(i \le j)\),一定是前面若干个 \(1\),然后跟若干个 \(0\)。
然后我们考虑转化问题,将问题转化成不断添加数字,容易发现第一个 \(b_{i,j}=0(i \le j)\) 的时刻 \(j\) 满足 \(\sum\limits_{k=1}^j [a_i=0] = i\)。所以可以考虑用前面的序列去推后面的部分。
考虑按当前 \(a_i\) 的值分类讨论:
当 \(a_i=0\) 时,有 \(\forall j \in [i,i+c_i-1],b_{i,j}=1\),以及 \(b_{i,i+c_i}=0\)。故在 \(i+c_i\) 的位置添加进去后有恰好 \(i\) 个 \(0\),故有 \(a_{i+c_i}=0\)。
当 \(a_i=1\) 时,有 \(\forall j \in [1,c_i],b_{i,j}=1\),以及 \(b_{i,c_i+1}=0\)。故在 \(c_+1i\) 的位置添加进去后有恰好 \(i\) 个 \(0\),故有 \(a_{c_i+1}=0\)。
对于没有被上面两种扫到的位置,显然可以当做 \(1\) 处理。
Code
//Think twice,code once.
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int T,n,a[200005];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) a[i]=1;
for(int i=1;i<=n;i++)
{
int c;
scanf("%d",&c);
if(c==0) a[i]=0;
if(a[i]==0) a[i+c]=0;
else a[c+1]=0;
}
for(int i=1;i<=n;i++) printf("%d ",a[i]);
puts("");
}
return 0;
}