题解 假人

Posted 欢迎,Administrator-09

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 假人相关的知识,希望对你有一定的参考价值。

传送门

像我这样的小蒟蒻并不能在没有std的情况下做出此题,不管是从思路上还是从代码实现上

  • 对于一类形如 \\(f_{i, j}=\\max\\limits_{1\\leqslant p\\leqslant min(k_i, j)}f_{i-1, j-p}+a_{i, p}\\),且保证 \\(a_{i, p}\\)\\(p\\) 单调不升/降问题的解法:
    发现只考虑 \\(i\\) 本身的贡献时dp值是凸的(此时就是 \\(a_{i, p}\\)
    然后发现 \\(i\\)\\(i-1\\) 间其实是独立的(因为 \\(p\\)\\(j\\) 无关,可以理解为把 \\(j\\) 拆成几个 \\(p\\) 分配给不同的 \\(i\\)
    于是可以分治,令 \\(f_{l, r, j}\\) 为给 \\([l, r]\\) 分配了 \\(j\\) 的最大贡献
    合并的话因为原来的转移实际上是一个不断取max的过程,决策点形成一个凸包
    可以贪心地按每个凸包上两个决策点之间的增量归并排序
    这个东西实际上是两个点集的闵可夫斯基和,这里的点集是原凸包
    实际意义的话,大概可以理解为原凸包做闵可夫斯基和得到的图形的边界是原DP所有合并的极值
    所以新凸包的边界上的点就是新的决策点了

回到这个题,发现 \\(a_{i, p}\\) 没有凸性,所以 \\(f_{i, i, j}\\) 也没有凸性,所以无法直接分治
但是神仙题解有神仙切入点……

于是可以按余数分组合并了
复杂度 \\(O(nk^2\\frac{n}{k}logn)=O(nklogn)\\)

然后代码实现上有个花了我巨久的细节:这题把范围从 \\([1, 5]\\) 调到了 \\([0, 4]\\),而我在凸包上维护长度的时候还在设法让下标从1开始
于是呢?炸,炸大个的

然后回来考虑一下题解切入用的结论
还有没有类似的满足 \\(sum=2*k\\),则一定能拆出 \\(sum=k\\) 的子集的数呢?见dalao博客

跟std基本一样的 Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define pb push_back
#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;
int siz[N], len[N];
ll a[N][6];

namespace task1{
	ll dp[1010][5010];
	void solve() {
		int sum=0;
		for (int i=1; i<=n; ++i) {
			for (int j=i-1; j<=sum; ++j) {
				for (int k=1; k<=siz[i]; ++k) {
					dp[i][j+k]=max(dp[i][j+k], dp[i-1][j]+a[i][k]);
				}
			}
			sum+=siz[i];
		}
		for (int i=n; i<=sum; ++i) printf("%lld ", dp[n][i]);
		printf("\\n");
		exit(0);
	}
}

namespace task2{
	priority_queue<ll> q;
	void solve() {
		ll ans=0;
		for (int i=1; i<=n; ++i) {
			if (siz[i]==2) q.push(a[i][2]-a[i][1]);
			ans+=a[i][1];
		}
		printf("%lld ", ans);
		while (q.size()) {
			ans+=q.top(); q.pop();
			printf("%lld ", ans);
		}
		printf("\\n");
		exit(0);
	}
}

namespace task{
	struct dat{
		vector<int> v[12];
		inline vector<int>& operator [] (int t) {return v[t];}
		void put() {
			cout<<"---dat---"<<endl;
			for (int i=0; i<12; ++i) {cout<<i<<": "; for (auto it:v[i]) cout<<it<<\' \'; cout<<endl;}
		}
	};
	void merge(dat& a, dat& b, dat& ans) {
		cout<<"merge: "<<endl;
		a.put(); b.put(); ans.put();
		for (int i=0; i<12; ++i) if (a[i].size()) {
			for (int j=0; j<12; ++j) if (b[j].size()) {
				int dlt=(i+j>=12), k=(i+j)%12, x=0, y=0;
				while (1) {
					ans[k][x+y+dlt]=max(ans[k][x+y+dlt], a[i][x]+b[j][y]);
					if (x==a[i].size()-1 && y==b[j].size()-1) break;
					else if (x==a[i].size()-1) ++y;
					else if (y==b[j].size()-1) ++x;
					else ++((a[i][x+1]-a[i][x]>b[j][y+1]-b[j][y])?x:y);
				}
			}
		}
		cout<<"return: "<<endl;
		ans.put();
	}
	dat solve(int l, int r) {
		// cout<<"solve: "<<l<<\' \'<<r<<endl;
		dat ans;
		if (l==r) {
			for (int i=1; i<=siz[l]; ++i) ans[(i-1)%12].pb(a[l][i]);
			return ans;
		}
		int tem=len[r]-len[l-1], mid=(l+r)>>1;
		// for (int i=0; i<tem+r-l; ++i) ans[i%12].pb(-1);
		for (int i=0; i<12; ++i)
			for (int j=i; j<=tem; j+=12) ans[i].pb(-1);
		dat a=solve(l, mid), b=solve(mid+1, r);
		merge(a, b, ans);
		return ans;
	}
	void enter() {
		dat ans=solve(1, n);
		// cout<<"ans: "<<endl;
		// ans.put();
		for (int i=0; i<=len[n]; ++i) printf("%lld%c", ans[i%12][i/12], " \\n"[i==len[n]]);
		exit(0);
	}
}

signed main()
{
	freopen("fake.in", "r", stdin);
	freopen("fake.out", "w", stdout);
	
	n=read();
	bool all_one=1, leq2=1;
	for (int i=1; i<=n; ++i) {
		siz[i]=read();
		len[i]=len[i-1]+siz[i]-1;
		if (siz[i]!=1) all_one=0;
		if (siz[i]>2) leq2=0;	
		for (int j=1; j<=siz[i]; ++j) a[i][j]=read();
	}
	// if (all_one || leq2) task2::solve();
	// else task1::solve();
	task::enter();
	
	return 0;
}

以上是关于题解 假人的主要内容,如果未能解决你的问题,请参考以下文章

在 Scope 中找不到“调整大小”,请 SwiftUI 解决假人问题

从书中复制C#代码(假人为C#.0,无法获得预期的结果

传奇gee引擎,智能假人,假人脚本,geeM2假人

带有 CUDA C 的假人点积

熊猫单热编码列到假人,包括“其他”编码[重复]

用AS3中的惯性拖动假人