D. Reverse Sort Sum

题目D. Reverse Sort Sum

考点: 线段树

题意:有一个长的为 n n n ,由 0 0 0 1 1 1 组成的数组,定义一个函数 f ( k , A ) f(k,A) f(k,A) ,它返回另一个数组 B B B ,即对 A A A 的前 k k k 个元素按非递减的顺序排序的结果。例如, f ( 4 , [ 0 , 1 , 1 , 0 , 1 , 0 ] ) = [ 0 , 0 , 1 , 1 , 1 , 0 ] f(4,[0,1,1,0,1,0]) = [0,0,1,1,1,0] f(4,[0,1,1,0,1,0])=[0,0,1,1,1,0] 。注意,前 4 4 4 个元素被排序。现考虑由 f ( 1 , A ) , f ( 2 , A ) , ⋅ ⋅ ⋅ , f ( n , A ) f(1,A),f(2,A),···,f(n,A) f(1,A),f(2,A),,f(n,A) 生成数组 B 1 , B 2 , ⋅ ⋅ ⋅ , B n B_1,B_2,···,B_n B1,B2,,Bn C C C 是通过取 B 1 , B 2 , ⋅ ⋅ ⋅ , B n B_1,B_2,···,B_n B1,B2,,Bn 的元素之和得到的数组。

例如,让 A = [ 0 , 1 , 0 , 1 ] A = [0,1,0,1] A=[0,1,0,1] ,则有 B 1 = [ 0 , 1 , 0 , 1 ] , B 2 = [ 0 , 1 , 0 , 1 ] , B 3 = [ 0 , 0 , 1 , 1 ] , B 4 = [ 0 , 0 , 1 , 1 ] B_1 = [0,1,0,1],B_2 = [0,1,0,1],B_3 = [0,0,1,1],B_4 = [0,0,1,1] B1=[0,1,0,1],B2=[0,1,0,1],B3=[0,0,1,1],B4=[0,0,1,1] ,得到的 C = B 1 + B 2 + B 3 + B 4 = [ 0 , 2 , 2 , 4 ] C = B_1 + B_2 + B_3 + B_4 = [0,2,2,4] C=B1+B2+B3+B4=[0,2,2,4]

现在得到数组 C C C ,需要按照上述的方法确定数组 A A A

思路:

  • 利用公式 k = ∑ 1 n C i n k = \frac{\sum_{1}^{n}{C_i}}{n} k=n1nCi 可以求出数组 A A A 中有都少个 1 1 1 ,利用最后一行的有序性,最后 k k k 个值一定为 1 1 1
  • B 1 B_1 B1 只有第 1 1 1 个有序, B 2 B_2 B2 只有前 2 2 2 个有序, B 3 B_3 B3 只有前 3 3 3 个有序,依此类推, B n − 1 B_{n-1} Bn1 只有前 n − 1 n-1 n1 个有序。当确定的第 n n n 行的第 n n n 个值时,用 C n − k n n − 1 \frac{C_n - k_n}{n-1} n1Cnkn 便是 A n A_n An 的值。
  • 在求 A n − 1 A_{n-1} An1 的时间需要先将 C k , . . . , n − 1 C_{k,...,n} - 1 Ck,...,n1 ,再用公式 k = ∑ 1 n − 1 C i n − 1 k = \frac{\sum_{1}^{n-1}{C_i}}{n-1} k=n11n1Ci ,接下来的思路与第二点相同。

需要注意的是,本题的数据会爆 i n t int int ,所以需要用 l o n g   l o n g long\text{ }long long long

在这里插入图片描述

#include<stdio.h>

typedef long long ll;
const int N = 2e5 + 10;
ll a[N],c[N];
struct node{
	int l,r;
	ll b,x;
}tr[4 * N];

void up(int p) {
	if(tr[p].x == 0) return ;
	tr[p * 2].b += tr[p].x * (tr[p * 2].r - tr[p * 2].l + 1);
	tr[p * 2 + 1].b += tr[p].x * (tr[p * 2 + 1].r - tr[p * 2 + 1].l + 1);
	
	tr[p * 2].x += tr[p].x;
	tr[p * 2 + 1].x += tr[p].x;
	tr[p].x = 0;
}

void build(int p,int l,int r) {
	tr[p].l = l;tr[p].r = r;tr[p].x = 0;tr[p].b = 0;
	if(l == r) {
		scanf("%lld",&tr[p].b);
		return ;
	}
	
	int mid = (l + r) >> 1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	
	tr[p].b = tr[p*2].b + tr[p*2+1].b;
}

void modify(int p,int l,int r,int x) {
	if(l <= tr[p].l && r >= tr[p].r) {
		tr[p].b += x * (tr[p].r - tr[p].l + 1);
		tr[p].x += x;
		return ;
	}
	
	up(p);
	
	int mid = (tr[p].l + tr[p].r) >> 1;
	
	if(mid >= l) modify(p*2,l,r,x);
	if(mid < r) modify(p*2+1,l,r,x);
	
	tr[p].b = tr[p*2].b + tr[p*2+1].b;
}

ll query(int p,int l,int r) {
	if(tr[p].l >= l && r >= tr[p].r) return tr[p].b;
	
	up(p);
	
	int mid = (tr[p].l + tr[p].r) >> 1;
	
	ll k = 0;
	
	if(mid >= l) k += query(p*2,l,r);
	if(mid < r) k += query(p*2+1,l,r);
	
	return k;
}

ll ask(int p,int k) {
	if(tr[p].l == tr[p].r) return tr[p].b;
	
	up(p);
	
	int mid = (tr[p].l + tr[p].r) >> 1;
	
	if(mid >= k) return ask(p*2,k);
	else return ask(p*2+1,k);
}

int main(){
	int t;
	scanf("%d",&t);
	while(t --) {
		int n;
		scanf("%d",&n);
		build(1,1,n);
		
		for(int i=n;i>=1;i--) {
			ll L = query(1,1,i) / i;
			
			if(i == 1) {
				a[i] = L;
				break;
			}
			
			if(L > 0) modify(1,i-L+1,i,-1);
			
			ll b = ask(1,i);
			
			a[i] = b / (i - 1);
			
		}
		for(int i=1;i<=n;i++) printf("%lld ",a[i]);
		printf("\n");
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值