CF1656B solution

Problem

给定序列 \(\{a_n\}\),求是否有一种顺序依次进行 \(n-1\) 次操作(每次将其中一个 \(a_i\) 从序列中删去,然后将剩下的每个 \(a_j\) 都减去 \(a_i\)),满足最后留下的数 \(=k\)

link->https://codeforces.com/contest/1656/problem/B

Solution

最暴力的想法是枚举 \(1\)\(n\) 的全排列,然后依次删除,判断最后留下来的值是否为 \(k\)。这样做时间复杂度为 \(\Theta(n^2\times n!)\),超时。

考虑更优的做法。

我们假设我们删除的顺序是 \(\{b_n\}\),即依次删除 \(a_{b_1},a_{b_2},\cdot\cdot\cdot,a_{b_n}\)

容易看出,每次删除 \(a_{b_i}\) 后,剩余的数与他们的初时值之差应该是一定的,即 \(\sum\limits_{i=1}^n a_{b_i}'\)

值得注意的一点是这里是 \(a_{b_i}'\) 而非 \(a_{b_i}\)。为什么呢?这里的 \(a_{b_i}'\) 指的是 \(a_{b_i}\) 在被删除前最后的值,即 \(a_{b_i}-\sum\limits_{j=1}^{i-1} a_{b_j}'\)

将其带入到 \(\sum\limits_{i=1}^n a_{b_i}'\) 里,则变为 \(\sum\limits_{i=1}^n (a_{b_i}-\sum\limits_{j=1}^{i-1} a_{b_j}')\)

我们不妨设 \(f_i\)\(\sum\limits_{j=1}^{i-1} a_{b_j}'\),容易发现,\(f_{i+1}\) 包含 \(f_i\) 的,即 \(f_{i+1}\) 可以写作递推公式 \(=f_i+x\)

同理,\(a_{b_{i+1}}-f_{i+1}\) 也是包含 \(f_i\) 的,则我们不妨将 \(a_{b_{i+1}}-f_{i+1}\) 写成 \(a_{b_{i+1}}-[f_i+(a_{b_i}-f_i)]=a_{b_{i+1}}-a_{b_i}\)

换言之,\(f_{i+1}=a_{b_i}\)

\(a_{b_i}'=\sum\limits_{i=1}^n (a_{b_i}-a_{b_{i-1}})\),将其展开后得 \(a_{b_i}'=a_{b_i}-a_{b_1}\)

我们要求 \(a_{b_n}'=k\) 即要求 \(a_{b_n}-a_{b_1}=k\)

题目变成寻找一个数对 \((i,j)\) 满足 \(a_i-a_j=k\)\(i>j\)

直接枚举复杂度为 \(\Theta(n^2)\),无法通过此题。

我们不妨把上式移一个项变为 \(a_i-k=a_j\),我们可以枚举 \(a_i\) 然后判断是否有 \(a_j=a_i-k\)。对于寻找 \(a_j\) 我们可以通过使用二分查找进行,也可以进行一个哈希,但略显繁琐。

下面给出二分查找代码。

Code

#include<bits/stdc++.h>
#define pd push_back
#define pb pop_back
#define mk make_pair
//#define int long long
#define PII pair<int,int>
#define _for(a,b,c) for(int a=b;a<=c;a++)
#define _rep(a,b,c) for(int a=b;a>=c;a--)
using namespace std;
template <typename T> inline void read(T& x) {
	x=0; T f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch&15); ch=getchar(); }
	x=x*f;
	return;
}
template <typename T,typename ...Arg> inline void read(T& x,Arg& ...arg){
	read(x); read(arg...);
}
int power(int a,int b) {
	int ans=1;
	do {
		if(b&1) ans*=a; a*=a;
	} while(b>>=1);
	return ans;
}
const int N=2e5+5;
int a[N],n,k,T;
signed main() {
	read(T);
	while(T--) {
		read(n,k);
		_for(i,1,n)
			read(a[i]);
		sort(a+1,a+n+1);
		bool have_ans=0;
		_for(i,1,n)
			if(a[lower_bound(a+1,a+n+1,a[i]-k)-a]==a[i]-k) {
				puts("YES"); have_ans=1; break;
			}
		if(!have_ans)
			puts("NO");
	}
	return 1;
}

posted @ 2022-08-01 14:07  lsj2009  阅读(35)  评论(0)    收藏  举报