题目
问题描述
分析
差分模拟
通过分析可以知道,序列 C C C中所有元素之和其实也就是原序列 A A A中 1 1 1的总和乘上 A A A的大小,换句话说我们可以利用 ∑ i = 1 n C i n \frac{\sum_{i=1}^{n}C_i}{n} n∑i=1nCi直接求出 1 1 1的个数。
我们此时已知
1
1
1的个数,也就相当于知道了序列
B
n
B_n
Bn的格式,那么我们就可以直接借助
C
n
C_n
Cn与
B
n
B_n
Bn求出
C
n
−
1
C_{n-1}
Cn−1以及在前
n
−
1
n-1
n−1次排序中始终未涉及的
a
n
a_n
an对
c
n
c_n
cn的总贡献,若
a
n
a_n
an为
1
1
1,则
a
n
a_n
an对
c
n
c_n
cn的贡献为
(
n
−
1
)
(n-1)
(n−1);若
a
n
a_n
an为0,则毫无贡献,这些可以由
C
i
−
1
C_{i-1}
Ci−1的
c
n
c_n
cn直接判断。
再判断
a
n
a_n
an的值后,我们也就得到了序列
B
n
−
1
B_{n-1}
Bn−1的格式,之后重复以上步骤即可。
另一个问题在于要如何由 C i + 1 C_{i+1} Ci+1、 B i + 1 B_{i+1} Bi+1求出 C i C_{i} Ci,假设 B i + 1 B_{i+1} Bi+1中 1 1 1的个数为 a n s ans ans,我们只需对 C i + 1 C_{i+1} Ci+1中尚未确定的后 a n s ans ans位减一即可,如果我们直接采用循环来做将会导致超时,这个时间复杂度为 O ( n 2 ) O(n^2) O(n2),我们可以借助树状数组+差分将其简化为 O ( n l o g n ) O(nlogn) O(nlogn).
代码
//差分模拟
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
#define fir(i, a, b) for (ll i = (a); i <= (b); i++)
#define rif(i, a, b) for (ll i = (a); i >= (b); i--)
const int N=2e5+5;
ll lowbit(ll x){
return x&(-x);
}
ll n,t,ans,tmp,a[N],b[N],sub[N];
ll sum(ll x){
ll tmp=0;
for(int i=x;i;i-=lowbit(i)){
tmp+=sub[i];
}
return tmp;
}
ll find(ll l){
return sum(l)-sum(l-1);
}
void add(ll pos,ll x){
for(ll i=pos;i<N;i+=lowbit(i)){
sub[i]+=x;
}
}
int main(){
cin>>t;
while(t--){
memset(b,0,sizeof b);
memset(sub,0,sizeof sub);
ans=0;
cin>>n;
fir(i,1,n){
cin>>a[i];
ans+=a[i];
add(i,a[i]-a[i-1]);
}
ans/=n;
tmp=n;
rif(i,n,1){
if(ans){
add(i-ans+1,-1);
tmp=sum(i);
if(tmp==i-1){
b[i]=1;
ans--;
}
// rif(j,i,i-ans+1){
// a[j]--;
// }
// if(a[i]==i-1){
// b[i]=1;
// ans--;
// }
}
else break;
}
fir(i,1,n)cout<<b[i]<<" ";
cout<<endl;
}
return 0;
}
//直接求解
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
#define fir(i, a, b) for (ll i = (a); i <= (b); i++)
#define rif(i, a, b) for (ll i = (a); i >= (b); i--)
const int N=2e5+5;
ll lowbit(ll x){
return x&(-x);
}
ll n,t,ans,tmp,a[N],b[N],c[N];
int main(){
cin>>t;
while(t--){
memset(b,0,sizeof b);
memset(c,0,sizeof c);
ans=0;
cin>>n;
fir(i,0,n-1){
cin>>a[i];
ans+=a[i];
}
ans/=n;
tmp=n-ans;
fir(i,tmp,n-1)b[i]=n-1;
for(int i=n-1;i>=0&&tmp<=i;i--){
if(a[i]-(b[i]-i)==i+1){
c[i]=1;
}
else if(a[i]-(b[i]-i)==1){
c[i]=0;
tmp--;
b[tmp]=i-1;
}
}
fir(i,0,n-1)cout<<c[i]<<" ";
cout<<endl;
}
return 0;
}