CSP2026多校联考Day3 C-混乱邪恶

先给出官方题解:

第一眼:写的什么玩意?
题解并没有给出构造方法,只有证明。
转换题意,即从这一堆数中选出来一些,使选出来数的和为所有数和一半。
于是我尝试借鉴倍增的思想,即任何数都可以拆成多个二的不同次幂的和,
将原数组备份,并按降序排序排序,即这些数的和的一半为 \(s\),依次尝试每一个数,如果这个数小于 \(s\) 就将其填入,并将 \(s\) 减去这个数的值,直到 \(s\) 为零,就构造出了一个合法方案。
但这个假了,这终究不是倍增,所以需要在此基础上写一个搜索:
96' code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int NUM=1e6+10;
int n,m;
int a[NUM],b[NUM];
int sum;
int vis[NUM];
bool dfs(int x,int s){
if(s<0) return 0;
if(s==0) return 1;
for(int i=x;i<=n;++i){
vis[b[i]]++;
if(dfs(i+1,s-b[i])) return 1;
vis[b[i]]--;
}
return 0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;++i){
cin>>a[i];sum+=a[i];b[i]=a[i];
}
sum/=2;
sort(b+1,b+1+n,[](int x,int y){
return x>y;
});
if(dfs(1,sum)){
cout<<"NP-Hard solved\n";
for(int i=1;i<=n;++i){
if(vis[a[i]]){
cout<<1<<' ';vis[a[i]]--;
}
else cout<<-1<<' ';
}
}else cout<<"Chaotic evil\n";
// cout<<dfs(1,sum)<<'\n';
return 0;
}
他T了。
于是我们考虑再看一眼题解:
题解构造了一个 \(d\) 数组,于是我受此启发,不是直接求 \(c\),而是求 \(e\) 来反推 \(c\)。
因为 \(d_i=b_{i\times 2 -1}-b_{i\times 2}\) (在我这里是这样的),所以当 \(e_i=1\) 时 \(b_{i\times 2 -1}\) 对应的 \(c_{b_{i\times 2 -1}}\) 的值为 \(1\),\(c_{b_{i\times 2}}\) 为 \(-1\)。
时间复杂度约为 \(O(kn)\),其中 \(k\) 是一个较小的常数,在特殊构造的题目还是会退化的。
100' code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int NUM=1e6+10;
int n,m;
int a[NUM],b[NUM],d[NUM];
int sum;
bool vis[NUM];
bool dfs(int x,int s){
if(s<0) return 0;
if(s==0) return 1;
for(int i=x;i<=(n+1)/2;++i){
vis[b[i*2-1]]^=1;vis[b[i*2]]^=1;
if(dfs(i+1,s-d[i])) return 1;
vis[b[i*2-1]]^=1;vis[b[i*2]]^=1;
}
return 0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;++i){
cin>>a[i];b[i]=a[i];
}
sort(b+1,b+1+n,[](int x,int y){
return x>y;
});
for(int i=1;i<=(n+1)/2;++i){
d[i]=b[i*2-1]-b[i*2];
vis[b[i*2-1]]=1;
sum+=d[i];
}
sum/=2;
if(dfs(1,sum)){
cout<<"NP-Hard solved\n";
for(int i=1;i<=n;++i){
if(vis[a[i]]){
cout<<1<<' ';
}
else cout<<-1<<' ';
}
}else cout<<"Chaotic evil\n";
return 0;
}

浙公网安备 33010602011771号