关于决策单调性dp的最优决策点
  • 板块学术版
  • 楼主gghack_Nythix
  • 当前回复0
  • 已保存回复0
  • 发布时间2024/7/24 13:06
  • 上次更新2024/7/24 14:39:04
查看原帖
关于决策单调性dp的最优决策点
895690
gghack_Nythix楼主2024/7/24 13:06

rt,我在写这一题的时候,使用了分治写法。但是我把最优决策点初始化为不一样的,分数也不一样,请问这是为什么?或者说什么写法是对的?

AC:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,vmx = 0,rdmod,best;
vector<int>newitem[300005];
struct node {
	int c,v;
}a[5000005];
int mdp[5000005],dp[5000005],fmdp[5000005];
int w(int mod,int r) {return newitem[mod][r];}
void solve(int l,int r,int pl,int pr) {
	if(l > r) return ;
	int mid = (l + r) >> 1;
	int qt = mid;
	mdp[mid] = fmdp[mid];
	for(int pos = pl;pos <= pr && pos < mid;++pos){
		if(mid - pos > newitem[rdmod].size()) continue;//判出界!!!!!
		if(mdp[mid] <= fmdp[pos] + w(rdmod,mid - pos - 1)) qt = pos,mdp[mid] = max(fmdp[pos] + w(rdmod,mid - pos - 1),mdp[mid]); 
	}
	if(l == r) return ;
	solve(l,mid - 1,pl,qt);
	solve(mid + 1,r,qt,pr);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	// freopen("jewelry18.in","r",stdin);
	// freopen("jewelry20.out","w",stdout);
	cin >> n >> k;
	for(int i = 1;i <= n;++i) cin >> a[i].c >> a[i].v,newitem[a[i].c].push_back((int)a[i].v),vmx = max(vmx,a[i].c);
	for(int i = 1;i <= vmx;++i) {
		if(newitem[i].empty()) continue;
		sort(newitem[i].begin(),newitem[i].end(), greater<int>() );
		for(int j = 1;j < (int)newitem[i].size();++j) newitem[i][j] += newitem[i][j - 1];
	}
	for(int i = 1;i <= vmx;++i) {
		if(newitem[i].empty()) continue;
		rdmod = i;
		for(int mod = 0;mod < i;++mod) {
			int tot = 0;
			for(int j = mod;j <= k;j += i) fmdp[++tot] = dp[j];//上一次的dp
			//j:同余的体积
			solve(1,tot,1,tot);
			//分治的实际上是同余的体积,分治的是倍数
			for(int j = 1,wl = mod;wl <= k;wl += i,++j) dp[wl] = mdp[j];
			//j:枚举的是mod+c_i*j中的j倍
		}
	}
	for(int j = k;j >= 1;--j) dp[j] = max(dp[j],dp[j - 1]);
	for(int i = 1;i <= k;++i) cout << dp[i] << " ";
	cout << '\n';
	return 0;
}

WA:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,vmx = 0,rdmod,best;
vector<int>newitem[300005];
struct node {
	int c,v;
}a[5000005];
int mdp[5000005],dp[5000005],fmdp[5000005];
int w(int mod,int r) {return newitem[mod][r];}
void solve(int l,int r,int pl,int pr) {
	if(l > r) return ;
	int mid = (l + r) >> 1;
	int qt = pl;//只有这里不一样
	mdp[mid] = fmdp[mid];
	for(int pos = pl;pos <= pr && pos < mid;++pos){
		if(mid - pos > newitem[rdmod].size()) continue;//判出界!!!!!
		if(mdp[mid] <= fmdp[pos] + w(rdmod,mid - pos - 1)) qt = pos,mdp[mid] = max(fmdp[pos] + w(rdmod,mid - pos - 1),mdp[mid]); 
	}
	if(l == r) return ;
	solve(l,mid - 1,pl,qt);
	solve(mid + 1,r,qt,pr);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	// freopen("jewelry18.in","r",stdin);
	// freopen("jewelry20.out","w",stdout);
	cin >> n >> k;
	for(int i = 1;i <= n;++i) cin >> a[i].c >> a[i].v,newitem[a[i].c].push_back((int)a[i].v),vmx = max(vmx,a[i].c);
	for(int i = 1;i <= vmx;++i) {
		if(newitem[i].empty()) continue;
		sort(newitem[i].begin(),newitem[i].end(), greater<int>() );
		for(int j = 1;j < (int)newitem[i].size();++j) newitem[i][j] += newitem[i][j - 1];
	}
	for(int i = 1;i <= vmx;++i) {
		if(newitem[i].empty()) continue;
		rdmod = i;
		for(int mod = 0;mod < i;++mod) {
			int tot = 0;
			for(int j = mod;j <= k;j += i) fmdp[++tot] = dp[j];//上一次的dp
			//j:同余的体积
			solve(1,tot,1,tot);
			//分治的实际上是同余的体积,分治的是倍数
			for(int j = 1,wl = mod;wl <= k;wl += i,++j) dp[wl] = mdp[j];
			//j:枚举的是mod+c_i*j中的j倍
		}
	}
	for(int j = k;j >= 1;--j) dp[j] = max(dp[j],dp[j - 1]);
	for(int i = 1;i <= k;++i) cout << dp[i] << " ";
	cout << '\n';
	return 0;
}
2024/7/24 13:06
加载中...