其他分享
首页 > 其他分享> > 牛客寒假训练营 3 C (多项式,逆dp)

牛客寒假训练营 3 C (多项式,逆dp)

作者:互联网

原题链接 

我们可以很自然的想到逆向思维

首先是逆拓扑时,我们的状态计算图如下

 可以分为 不买买半个买整个 三个子集

所以对于背包容积为m的背包来说,瓜最多重 2m

然后是正拓扑时,因为一个集合可以递推到三个集合,我们就可以从一个集合找到他的三个父集合

,那么在递推的时候,就可以使用正向递推算出答案

正向递推

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e3 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
ll dp[N];
vector<int> ans;
int main()
{
	int m;
	cin >> m;
	dp[0] = 1;//dp[i][0]一定为1
	for (int i = 1;i <= m;i++)
		cin >> dp[i];
	for (int i = 1;i <= m;i++)
	{//瓜重
		while (dp[i])
		{
			ans.push_back(2 * i);
			for (int j = 0;j <= m;j++)
			{//背包容积
				if (j + i <= m)
					dp[j + i]  -= dp[j];
				while (j + i <= m && dp[j + i] < 0) dp[j + i] += mod;
				if (j + i + i <= m)
					dp[j + i + i] -=dp[j];
				while (j + i + i <= m && dp[j+ i + i] < 0) dp[j + i + i] += mod;

			}
		}
	}
	cout << ans.size()<<endl;
	for (auto t : ans)
		cout << t << ' ';

}

 逆向递推

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e3 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
ll dp[N];
vector<int> ans;
int main()
{
	int m;
	cin >> m;
	dp[0] = 1;
	for (int i = 1;i <= m;i++)
		cin >> dp[i];
	for (int w = 1;w <= m;w++)//物品
	{
		while (dp[w])
		{
			ans.push_back(2 * w);
			for (int j = 0;j <= m;j++)
			{//总重
				if (j - w >= 0)
					dp[j] -= dp[j - w];
				while (j - w >= 0 && dp[j] < 0) dp[j] += mod;
				if (j - 2 * w >= 0)
					dp[j] -= dp[j - w * 2];
				while (j - 2 * w >= 0 && dp[j] < 0) dp[j] += mod;
			}
		}
	}
	cout << ans.size()<<endl;
	for (auto t : ans)
		cout << t << ' ';

}

标签:const,int,训练营,long,牛客,include,ll,dp
来源: https://blog.csdn.net/qq12323qweeqwe/article/details/122809710