题解 [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;
}