P1108 低价购买
链接
https://www.luogu.com.cn/problem/P1108
思路
最长不降子序列。用dp方法是n2;非dp方法是nlog2n。这里只能用dp方法,因为要统计有多少个。
具体思路就是用两个数组:f[N],c[N]。前者:正常记录最长子序列:fi = max{fj+1},i>j&&f[i]<f[j]。后者计数:1.对j<i && f[i] == f[j]+1,c[i]+=c[j];2.对j<i &&f[i] == f[j],c[j]=0。第二条可以避免重复计数
同时注意不能马上加(参考错误代码,会加多)
WA代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
using namespace std;
const int N = 5e3 + 10;
int n;
int a[N];
int f[N], c[N];
signed main()
{
IOS;
cin >> n;
for (int i = 1; i <= n; i++) { cin >> a[i]; f[i]= 1; }
int maxlen = 1;
for (int i = 2; i <= n; i++)
{
for (int j = 1; j < i; j++)
{
if (a[j] > a[i])
{
f[i] = max(f[i], f[j] + 1);
}
}
maxlen = max(maxlen, f[i]);
}
int ans = 0;
c[1] = 1;
for (int i = 2; i <= n; i++)
{
if (f[i] == 1)c[i] = 1;
for (int j = 1; j < i; j++)
{
if (a[j] == a[i] and f[i] == f[j])
{
c[j] = 0;
}
else if (a[j] > a[i] and f[i] == f[j] + 1)
{
c[i] += c[j];
}
}//这里的区别,不能马上加,否则第二条原则就失效了
if (f[i] == maxlen)ans += c[i];
}
cout << maxlen << ' ' << ans;
return 0;
}
AC代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
using namespace std;
const int N = 5e3 + 10;
int n;
int a[N];
int f[N], c[N];
signed main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) { cin >> a[i]; f[i]= 1; }
int maxlen = 1;
int ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < i; j++)
{
if (a[j] > a[i])
{
f[i] = max(f[i], f[j] + 1);
}
}
maxlen = max(maxlen, f[i]);
if (f[i] == 1)c[i] = 1;
for (int j = 1; j < i; j++)
{
if (a[j] == a[i] && f[i] == f[j])
{
c[j] = 0;
}
else if (a[j] > a[i] and f[i] == f[j] + 1)
{
c[i] += c[j];
}
}
}//这里的区别,不能马上加,否则第二条原则就失效了
for (int i = 1; i <= n; i++)
{
if (f[i] == maxlen)
ans += c[i];
}
cout << maxlen << ' ' << ans;
return 0;
}

浙公网安备 33010602011771号