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;
}

浙公网安备 33010602011771号