首页 > 其他分享 >P2687 [USACO4.3] 逢低吸纳 题解

P2687 [USACO4.3] 逢低吸纳 题解

时间:2023-11-12 17:22:05浏览次数:34  
标签:arr USACO4.3 题解 P2687 int num ans dp define

双倍经验

分析

这是一道求最长下降子序列的题目,且要统计方案,但是会有重复情况,例如以下的的数据,

4
4 2 2 3

我们可以选择 \(1, 2\), \(1, 2\), \(1, 4\) 这几天来购买,但是 \(1, 2\) 和 \(1, 3\) 本质上是一样的,所以只算一种。

根据上面的说明,我们可以得出:

  • 当 \(dp_j + 1 = dp_i\) 而且 \(a_j > a_i\),\(i\) 的方案数加上 \(j\) 的方案数。
  • 当 \(dp_j = dp_i\) 而且 \(a_j = a_i\),\(j\) 的方案数清零。

其中 \(dp_i\) 指以第 \(i\) 个数为结尾的最长公共下降子序列长度,\(a_i\) 指第 \(i\) 天的股票价格。

90 pts Code

/*Code By Manipula*/
#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define INF 0x3f3f3f3f
#define int long long
#define swap(x, y) x ^= y ^= x ^= y
#define sqrt(n) pow(n, 0.5)
#define sort stable_sort
#define mk(x, y) make_pair(x, y)
#define mt(arr, num) memset(arr, num, sizeof(arr))
using namespace std;
const int N = 5005;
int dp[N], a[N], ans[N], n, last, sum;
signed main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)cin >> a[i];
	for (int i = 1; i <= n; i++)dp[i] = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j < i; j++)
			if (a[j] > a[i])dp[i] = max(dp[i], dp[j] + 1);
		if (dp[i] > dp[last])last = i;
	}
	for (int i = 1; i <= n; i++)
	{
		if (dp[i] == 1)ans[i] = 1;
		for (int j = 1; j < i; j++)
			if (a[j] > a[i] && dp[j] + 1 == dp[i])ans[i] += ans[j];
			else if (a[j] == a[i] && dp[j] == dp[i])ans[j] = 0;
	}
	for (int i = 1; i <= n; i++)
		if (dp[i] == dp[last])sum += ans[i];
	cout << dp[last] << " " << sum;
	return 0;
}

为什么是 90 pts 代码?因为这题要打十分讨厌的高精度!!

下面给出加上了高精度的代码。

Accepted Code

/*Code By Manipula*/
#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define INF 0x3f3f3f3f
#define int long long
#define swap(x, y) x ^= y ^= x ^= y
#define sqrt(n) pow(n, 0.5)
#define sort stable_sort
#define mk(x, y) make_pair(x, y)
#define mt(arr, num) memset(arr, num, sizeof(arr))
using namespace std;
const int N = 5005;
const int base = 1e18;
int dp[N], a[N], n, last;
struct BIGNUM{
	int num[N], len;
	void meset(){mt(num, 0); len = 1;}
	BIGNUM operator + (BIGNUM a) const {
		BIGNUM res = (BIGNUM){{}, max(a.len, len)};
		for (int i = 1; i <= res.len; i++)
		{
			res.num[i] += a.num[i] + num[i];
			res.num[i + 1] += res.num[i] / base;
			res.num[i] %= base;
		}
		if (res.num[res.len + 1])res.len++;
		return res;
	}
	void print()
	{
		for (int i = len; i; i--)
			if (i == len)cout << num[i];
			else cout << setw(18) << setfill('0') << num[i];
	}
}ans[N], sum;
signed main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)cin >> a[i];
	for (int i = 1; i <= n; i++)dp[i] = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j < i; j++)
			if (a[j] > a[i])dp[i] = max(dp[i], dp[j] + 1);
		if (dp[i] > dp[last])last = i;
	}
	for (int i = 1; i <= n; i++)
	{
		if (dp[i] == 1)ans[i] = (BIGNUM){{0, 1}, 1};
		for (int j = 1; j < i; j++)
			if (a[j] > a[i] && dp[j] + 1 == dp[i])ans[i] = ans[i] + ans[j];
			else if (a[j] == a[i] && dp[j] == dp[i])ans[j].meset();
	}
	for (int i = 1; i <= n; i++)
		if (dp[i] == dp[last])sum = sum + ans[i];
	cout << dp[last] << " ";
	sum.print();
	return 0;
}

标签:arr,USACO4.3,题解,P2687,int,num,ans,dp,define
From: https://www.cnblogs.com/Manipula/p/17827433.html

相关文章

  • [题解] P9838 挑战 NPC IV
    P9838挑战NPCIV定义\(f(x)=1+\log_2\operatorname{lowbit}(x)\)。定义一个\(1\simn\)的排列\(p\)的权值是\(\sum_{l=1}^n\sum_{r=l}^n\sum_{i\in[l,r]}f(p_i)。\)求所有\(1\simn\)的排列中权值第\(k\)小的排列的权值,对\(998244353\)取模。......
  • 【2023 #84】 锦城ACM周测 (大二个人赛) 题解
    题目难度\(B<D<E=C<A\)A:提高+/省选-B:普及-C:普及/提高-D:普及/提高-E:普及/提高-CandywarQuestion有\(N\)个盒子摆成环形,第\(i\)和盒子里面有\(a_i\)个糖果,他们开始在\(1\)好盒子,然后每个人取一次,可以取\(1\),或者小于当前盒子内糖果数的一个质数\(p\),......
  • chatgpt的api联网报错问题解决:openai公司的api联网报错解决
    chatgpt是啥,这里不讲,openai是啥这里也不讲。要知道我们不论是通过网页web使用chatgpt还是使用api方式通过客户端使用chatgpt都是需要使用外国IP的,     ......
  • 「题解」P6791 [SNOI2020] 取石子
    anti-game没有用,能取到\(n-1\)的必胜,不能取到\(n-1\)的必败,所以现在考虑取走最后石子获胜的情况。对于一个\(n\)来说合法的\(k\)一定是一个前缀,并且一定是贪心取最小的(留给对方的机会更小),所以启发将每个\(n\)最小的合法的\(k=a_n\)打出表来,找到最小的\(j\)满足\(......
  • 【洛谷 P2669】[NOIP2015 普及组] 金币 题解(循环)
    [NOIP2015普及组]金币题目背景NOIP2015普及组T1题目描述国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金币……;这种工资发放模式会一直这......
  • ABC 328 题解
    A直接模拟即可。cin>>n>>m;for(inti=1;i<=n;++i){ intx;cin>>x; if(x<=m)sum+=x;}cout<<sum;B直接模拟即可。intn,ans;boolchk(intx,inty){ intdig=x%10;x/=10; while(x){ if(x%10!=dig)return0; x/=10; } while(y){ if(y%10......
  • ABC328F 题解
    blog。提供一个普通并查集+启发式合并做法。考虑直接维护\(X_i\)。对于\(X_u-X_v=w\),分四种情况。\(X_u,X_v\)都没被维护过。直接钦定\(X_u\getsw,X_v\gets0\),以后再改。\(X_u\)没被维护过,\(X_v\)被维护过。显然\(X_u\getsX_v+w\)。\(X_v\)没被维护过,\(X_u\)被......
  • ABC328G 题解
    blog。剩下几分钟的时候胡出来了,但是时间不够,痛失AK/dk。\(N\le22\),显然状压DP。\(dp_s\)表示确定\(s\)集合的元素所需的代价(这些元素都放在最前面)。确定了\(s\)后,发现会有\(\operatorname{popcount}(s)\)个元素堆在前面,那么枚举\([L,R]\)接在后面,也就是\([\opera......
  • [题解] CF407E k-d-sequence
    k-d-sequence给你一个长为\(n\)的序列,求最长的子区间使得它加入至多\(k\)个数后,重排后是公差为\(d\)的等差数列。\(n,k\le2\times10^5\),\(0\led\le10^9\)。公差是\(d\)的等差数列模\(p\)的值应该相等,所以把序列按极长模\(p\)同余的连续段分组。对于同......
  • [题解] CF505E Mr. Kitayuta vs. Bamboos
    Mr.Kitayutavs.Bamboos给定\(n\)个数\(h_{1\dotsn}\)。你需要进行\(m\)轮操作,每轮操作为\(k\)次修改,每次修改可以选择一个数\(h_i\)修改为\(\max(h_i-p,0)\)。每轮操作后每个\(h_i\)将会被修改为\(h_i+a_i\)。你需要最小化最终\(h_{1\cdotsn}\)中......