2020小米邀请赛网络选拔赛第二场H Knapsack 决策单调性优化大容量多重背包 分治

https://ac.nowcoder.com/acm/contest/7502/H

学习自

https://blog.csdn.net/qq_30361651/article/details/109477637

无论是分治还是单调队列搞二分都是O(w m logm)的,叉姐题解说的SMAWK算法中文网上都查不到相关的题解或者算法笔记,维基百科上倒是有。。。还是不学了,这个时限也是放log过的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=2e5+10;
const ll inf=1ll<<61;

int n,m;
ll f[maxl],sum[maxl],g[maxl],ng[maxl];
vector<int> a[maxl];

inline void prework()
{
	for(int i=1;i<=100;i++)
		a[i].clear();
	for(int i=0;i<=m;i++)
		f[i]=0;
	for(int i=1;i<=n;i++)
	{
		int w,v;scanf("%d%d",&w,&v);
		a[w].push_back(v);
	}
}

inline void dp(int len,int l,int r,int l1,int r1)
{
	ll mx=-inf;
	int id=0,mid=(l+r)>>1;
	for(int i=max(l1,mid-len);i<=min(r1,mid);i++)
	if(mx<g[i]+sum[mid-i])
		mx=g[i]+sum[mid-i],id=i;
	ng[mid]=mx;
	if(l<=mid-1)
		dp(len,l,mid-1,l1,id);
	if(mid+1<=r)
		dp(len,mid+1,r,id,r1);
}

inline bool cmp(const int &x,const int &y){return x>y;}

inline void solv(int x)
{
	int l=a[x].size();
	if(!l)
		return;
	sort(a[x].begin(),a[x].end(),cmp);
	for(int i=1;i<=l;i++)
		sum[i]=sum[i-1]+a[x][i-1];
	for(int i=0;i<x;i++)
	{
		int tp=0;
		for(int j=i,k=1;j<=m;j+=x,k++)
			g[k]=f[j],tp=k;
		g[0]=0;
		dp(l,1,tp,1,tp);
		for(int j=i,k=1;j<=m;j+=x,k++)
			f[j]=ng[k];
	}
}

inline void mainwork()
{
	for(int i=1;i<=100;i++)
		solv(i);
}

inline void print()
{
	ll ans=0;
	for(int i=1;i<=m;i++) ans=max(ans,f[i]);
	printf("%lld\n",ans);
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/111236254
今日推荐