Logo zibenlun 的博客

博客

玄学算法——模拟退火

...
zibenlun
2025-12-01 12:58:15
分块好啊

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2023-08-06 10:56:50

一定要通过啊!

歪解

看到题解里都是折半(或叫双端)搜索,那我就来发一个随便乱搞 模拟退火。

考场利器

模拟退火

由于我们不知道选几个数,所以直接暴力出选择的长度,再来跑上几遍 SA。

#include<bits\/stdc++.h>
using namespace std;
int n,m;
long long a[1000005];
long long ans;
long long check(int len){
	long long cnt=0;
	for(int i=1;i<=len;i++){
		cnt+=a[i];
	}
	if(cnt<=m) return cnt;
	else return 0;
}
void SA(int len){
	double t=rand()%6000,x=0.682755;
	while(t>1e-15){
		int l=rand()%(len)+1,r=min(rand()%(n-len+1)+len,n);
		swap(a[l],a[r]);
		long long sum=check(len);
		if(sum>ans){
			ans=sum;
		}
		else {
			if(rand()*pow(x,100)>t) swap(a[l],a[r]);
		}
		t*=x;
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=10000;j++) SA(i);
	}
	cout<<ans;
	return 0;
}

正解

没什么讲的必要,纯纯模版题,双端搜完再二分拼合就行了。

#include<bits\/stdc++.h>
using namespace std;
long long a[1100005],b[1100005],s[55],ans,m,cntt,cnt,n;
void dfs1(int x,long long sum){
	if(sum>m) return;
	if(x>n\/2){
		a[++cnt]=sum;
		return;
	}
	dfs1(x+1,sum+s[x]);
	dfs1(x+1,sum);
}
void dfs2(int x,long long sum){
	if(sum>m) return;
	if(x>n){
		b[++cntt]=sum;
		return;
	}
	dfs2(x+1,sum+s[x]);
	dfs2(x+1,sum);
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>s[i];
	dfs1(1,0);
	dfs2(n\/2+1,0);
	sort(a+1,a+cnt+1);
	sort(b+1,b+cntt+1);
	for(int i=1;i<=cnt;i++) ans=max(ans,b[upper_bound(b+1,b+cntt+1,m-a[i])-b-1]+a[i]);
	cout<<ans;
	return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。