牛客寒假训练营 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