题解 [CF1239E] Turtle

传送门

算是相对简单的一道
可以发现最优策略下第一行一定升序,第二行一定降序
那在这个条件下乌龟一定会把其中一行和左上右下两个角全走完
那就是要将去掉最小的两个数后的序列分为两部分,使和的最大值最小,并输出方案
bitset 优化背包即可
复杂度 \(O(\frac{n^3V}{\omega})\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
bool vis[N];
int a[N], sta[N], ans=INF, sum, top, cnt;
bitset<1250005> f[52][26];

signed main()
{
	// cout<<double(sizeof(f))/1000/1000<<endl;
	n=read(); m=n<<1;
	for (int i=1; i<=m; ++i) a[i]=read();
	sort(a+1, a+m+1);
	for (int i=3; i<=m; ++i) sum+=a[i];
	f[2][0][0]=1;
	for (int i=3; i<=m; ++i)
		for (int j=0; j<n; ++j)
			f[i][j]|=f[i-1][j],
			f[i][j+1]|=f[i-1][j]<<a[i];
	for (int i=f[m][n-1]._Find_first(); i<1250005; i=f[m][n-1]._Find_next(i))
		ans=min(ans, max(i, sum-i));
	// cout<<"ans: "<<ans<<endl;
	int pos, now, cnt=n-1;
	for (pos=f[m][n-1]._Find_first(); ; pos=f[m][n-1]._Find_next(pos))
		if (max(pos, sum-pos)==ans) break;
	for (now=m; now>2&&cnt; --now)
		if (pos>=a[now] && f[now][cnt-1][pos-a[now]]) sta[++top]=a[now], --cnt, pos-=a[now];
		else vis[now]=1;
	while (now>2) vis[now--]=1;
	printf("%d ", a[1]);
	while (top) printf("%d ", sta[top--]);
	printf("\n");
	for (int i=m; i>2; --i) if (vis[i]) printf("%d ", a[i]);
	printf("%d\n", a[2]);
	
	return 0;
}
posted @ 2022-03-03 22:05  Administrator-09  阅读(3)  评论(0编辑  收藏  举报