CF1809C Sum on Subarrays 题解

CF1809C Sum on Subarrays

一道黄题做了一上午我可以退役了。

构造题。由于直接构造并不是那么容易,所以考虑在一个初始元素全为 \(-1\) 的序列上构造。

考虑将一个负数改为正数 \(1000\) 对答案造成的贡献(因为取 \(1000\) 计算比较方便)。设在放置这个正元素之前已经放置了 \(x\) 个正元素,则这个正元素会造成 \(n-x\) 的贡献,也就是会创造 \(n-x\) 个新的正区间。

原因显然,由于负数均为 \(-1\)\(n\) 又小于等于 \(30\)\(1000\) 相当于正无穷,所以从这个元素到序列中的任何一个位置都是正区间。如果某一个位置已经是 \(1000\) 了,那么在插入之前的这个 \(1000\) 时已经计算了这一段区间,需要减去不计算,所以贡献为 \(n-x\)

由于位置无关,我们尽量把 \(1000\) 往后放,如果再放一个 \(1000\) 就超过了正区间的数量,我们考虑在前面创造一些单独的正区间。设剩下的数为 \(s\),则我们将第一个数改为 \(200\),很明显,这也相当于一个正无穷。然后,我们要把第 \(s+1\) 个位置的数改为 \(-400\),消除 \(200\) 对后面的数的影响。由于之前放的数是 \(1000\),所以 \(-400\) 并不会影响其正无穷性质。

第一个数 \(200\) 可以把从第一个数开始到 \(s+1\) 以前的区间变成正区间,刚好是 \(s\) 个正区间,刚好符合要求。

#include <bits/stdc++.h>
using namespace std;
long long t,n,k,a[40];
int main()
{
	scanf("%lld",&t);
	while(t--)
	   {
		scanf("%lld%lld",&n,&k);
		long long now=n;
		for(int i=1;i<=n;i++)a[i]=-1;
		for(int i=n;i>=1;i--)
		    if(k>=now)a[i]=1000,k-=now,now--;
		    else break;
		if(k!=0)a[1]=200,a[k+1]=-400;
		for(int i=1;i<=n;i++)printf("%lld ",a[i]);
	    printf("\n");
	   }
	return 0;
}

AC记录

posted @ 2025-02-14 18:26  w9095  阅读(8)  评论(0)    收藏  举报