CF1552D题解

CF1552D题解

思路

首先, a i a_i ai 的正负不重要,如果 a i = b j − b k a_i=b_j-b_k ai=bjbk,那么就有 − a i = b k − b j -a_i=b_k-b_j ai=bkbj,读入时将 a i a_i ai 全部转化为正数。

若满足 a i + a j + … + a k a_i+a_j+\ldots+a_k ai+aj++ak,那么就可以构造出 b b b 序列,否则不行。

从左到右遍历一遍 a a a 序列,动态规划推出所有可以组成的和,并判断是否满足上式,时间复杂度 O ( T × n × max ⁡ ( a i ) ) O(T\times n\times \max(a_i)) O(T×n×max(ai))

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int T,n,dp[N],a[20];

void solve(){
	for(int i=0;i<N;i++) dp[i]=0;
	cin>>n; dp[0]=1; bool flag=false;
	for(int i=0;i<n;i++){ cin>>a[i]; a[i]=a[i]<0?-a[i]:a[i]; }
	for(int i=0;i<n;i++)
		for(int j=N-1-a[i];j>=0;j--)
			if(dp[j]){
				if(dp[j+a[i]]==1) flag=true;
				else dp[j+a[i]]=1;
			}
	cout<<(flag?"YES\n":"NO\n");
}
-
signed main(){
	ios::sync_with_stdio(false);
	for(cin>>T;T;T--) solve();
}

现在抛出一个不难验证的结论:若 a i    o p    a j    o p …    a k    o p    a l = 0 a_i\;\mathcal{op}\;a_j\;\mathcal{op}\ldots\;a_k\;\mathcal{op} \;a_l=0 aiopajopakopal=0 o p op op + + + − -
那么就可以构造出序列 b b b,否则不能。
那么对于 a a a 序列中的所有数,有三种情况:

  1. a i a_i ai 不在上面式子中。
  2. a i a_i ai 在上式中, o p op op + + +
  3. a i a_i ai 在上式中, o p op op − -

3 n − 1 3^n-1 3n1 种状态(因为不能全部不在上式中,所以减去 1 1 1 种情况)。

遍历 1 1 1 次这种状态,若有一种情况符合上式,那么就输出 yes,时间复杂度 O ( n × 3 n ) O(n\times3^n) O(n×3n)

#include<bits/stdc++.h>
using namespace std;
int T,n,a[20];

void solve(){
	cin>>n; int k=pow(3,n);
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=1;i<k;i++){
		int sum=0,tk=i;
		for(int j=0;j<n;j++){
			int s=tk%3; tk/=3;
			if(s==2) s=-1;
			sum+=s*a[j];
		}
		if(sum==0) return (void)(cout<<"YES\n");
	}
	cout<<"NO\n";
}

signed main(){
	ios::sync_with_stdio(false);
	for(cin>>T;T;T--) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值