低价购买
题目描述
“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价,你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。
这里是某支股票的价格清单:
$$
\def\arraystretch{1.5}
\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
\textsf{日期} & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 11 & 12 \cr\hline
\textsf{价格} & 68 & 69 & 54 & 64 & 68 & 64 & 70 & 67 & 78 & 62& 98 & 87 \cr\hline
\end{array}
$$
最优秀的投资者可以购买最多 $4$ 次股票,可行方案中的一种是:
$$
\def\arraystretch{1.5}
\begin{array}{|c|c|c|c|c|}\hline
\textsf{日期} & 2 & 5 & 6 & 10 \cr\hline
\textsf{价格} & 69 & 68 & 64 & 62 \cr\hline
\end{array}
$$
输入格式
第一行共一个整数 $N\ (1 \le N \le 5000)$,股票发行天数
第二行一行 $N$ 个整数,是每天的股票价格。保证是大小不超过 $2^{16}$ 的正整数。
输出格式
输出共一行两个整数,分别为最大购买次数和拥有最大购买次数的方案数(数据保证 $ \le 2^{31}$)当二种方案“看起来一样”时(就是说它们构成的价格队列一样的时候),这 $2$ 种方案被认为是相同的。
样例输入 #1
12
68 69 54 64 68 64 70 67 78 62 98 87
样例输出 #1
4 2
思路
令f[i]表示以数字a[i]结尾且长度为dp[i]的方案数,那么当a[i]!=a[j]时,出现dp[i]=dp[j]+1的情况,直接在**f[i]加上f[j],但当a[j]=a[i]时,因为我们对f[i]的定义可得,f[i]和f[j]**此时是有重合的,也就是说只保留一个最多方案的f[i]即可
最后遍历一遍数组,加上所有等于答案长度的方案数即可
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int N=1e5+10;
const int mod=1e9+7;
int dp[N],a[N];
int f[N];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i]=f[i]=1;
}
int ans1=1;
for(int i = 2; i <= n; i++) {
for(int j = 1; j < i; j++){
if(a[i] < a[j]) {
if(dp[i]<dp[j]+1){
dp[i] = max(dp[i], dp[j] + 1);
f[i]=f[j];
}
else if(dp[i]==dp[j]+1) f[i]+=f[j];
}
if(a[i]==a[j]) dp[j]=f[j]=0;
}
ans1 = max(ans1, dp[i]);
}
int num=0;
for(int i=1;i<=n;i++){
if(dp[i]==ans1) num+=f[i];
}
cout<<ans1<<' '<<num<<endl;
}
signed main()
{
int t=1;
//cin>>t;
while(t--)
{
solve();
}
}
同样的记录背包最优方案数在acwing有一道板题
这里用g[i]表示背包体积为i时的最优方案数
如果选第i个物品能做到让价值增加,那么舍弃掉原先的方案数,用g[j-v]的值来覆盖掉g[j];
如果选与不选对结果没有影响,即价值一样时,需要把两种状态的方案汇总到一起,g[j]+=g[j-v];
最后的g[V]即是最优情况下的方案总和
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
const int mod=1e9+7;
int dp[N];
int a[N],b[N];
int n,V;
vector<int>e[N];
int g[N];
void solve()
{
int n,V;
cin>>n>>V;
for(int i=0;i<=V;i++) g[i]=1;
for(int i=1;i<=n;i++)
{
int v,w;
cin>>v>>w;
for(int j=V;j>=v;j--)
{
if(dp[j]<dp[j-v]+w)
{
dp[j]=dp[j-v]+w;
g[j]=g[j-v];
}
else if(dp[j]==dp[j-v]+w)
{
g[j]+=g[j-v];
g[j]%=mod;
}
}
}
cout<<g[V]<<endl;
}
signed main()
{
int t=1;
//cin>>t;
while(t--)
{
solve();
}
}