cf场+线性dp

Problem - B - Codeforces

思路:

这其实是一道数学题(最开始一直在枚举,服啦)

我们的目的是求最大利润

当a>=b是时直接令k=0,利润=n*a即可

当a<b时存在两种情况:

1.b-a>=n即所有b-i+1的情况都>a,这个时候我们把b-i+1看成一个等差数列求和即可

2.n>b-a>0这种情况我们还需要考虑到使用到的a,在此之前我们按照等差数列出售了(b-a)个,那么剩下n-(b-a)个我们则需要按照a来出售

还可以参考我觉得挺好的一篇题解:

题解:CF1978B New Bakery-CSDN博客

AC代码:

void solve()
{
	ll n, a, b, ans;
	cin >> n >> a >> b;
	if (a >= b)
	{
		cout << a * n << endl;
		return;
	}
	else
	{
		ll k = min(n, b - a);
		cout << (b + b - k + 1) * k / 2 + a * (n - k) << endl;
		return;
	}
	return;
}

Problem - B - Codeforces

思路:

采用双指针,一个指向a的头部,一个指向b的头部,两者开始进行匹配,若相同则b往下走一位,否则就终止

AC代码:

void solve()
{
	ll n, m;
	cin >> n >> m;
	cin >> a >> b;
	a = " " + a, b = " " + b;//相当于char a[],然后cin>>a+1
	ll sum = 0, j = 1;
	for (int i = 1; i <= n; i++)
	{
		for (; j <= m; j++)
		{
			if (a[i] == b[j])
			{
				sum++;
				j++;
				break;
			}
		}
		if (j > m)
			break;
	}

	cout << sum << endl;
	return;
}

还有一篇动态规划的题解我感觉也不错

Prefiquence(双指针,动态规划)-CSDN博客

代码奉上:

void solve()
{
	ll n, m;
	cin >> n >> m;
	cin >> a >> b;
	a = " " + a, b = " " + b;
	dp[1] = (a[1] == b[1] ? 1 : 0);
	for (int i = 2; i <= m; i++)
	{
		if (dp[i - 1] < n && a[dp[i - 1] + 1] == b[i])
		{
			dp[i] = dp[i - 1] + 1;
		}
		else
		{
			dp[i] = dp[i - 1];
		}
	}
	cout << dp[m] << endl;
	return;
}

Problem - C - Codeforces

思路:

令a[1]=x[1]+1后我们可以让a[i+1]=a[i]+x[i],但是这样的话数可能会比较小,所以我们可以累加a[i],因为是mod所以只要不大于x[i+1]可以一直加下去

代码:

void solve()
{
	int n;
	cin >> n;
	for (int i = 1; i < n; i++)
		cin >> x[i];
	a[1] = x[1] + 1;
	for (int i = 1; i < n; i++)
	{
		a[i + 1] = a[i] + x[i];
		while (a[i + 1] <= x[i + 1])
		{
			a[i + 1] += a[i];
		}
	}
	for (int i = 1; i <= n; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
	return;
}

P1020 [NOIP1999 提高组] 导弹拦截 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目的第一问其实就是让我们求最长不上升子序列,第二问就是求有多少段最长不上升序列

dp代码:

void solve2()
{
	int res = 0;
	for (int i = 0; i < n; i++)
	{
		dp[i] = 1;
		for (int j = 0; j < i; j++)
		{
			if (a[j] > a[i])
			{
				dp[i] = max(dp[i], dp[j] + 1);
			}
		}
		res = max(res, dp[i]);
	}
	cout << ans << endl;
	return;
}

然后我们发现就只会有50分,因为这个代码的时间复杂度达到了n^2,和题目的要求时间复杂度差距非常大,我们改善一下

void solve()
{
	vector<int>c;
	int ans = 0;
	while (cin >> a[num])
	{
		dp[num] = 1;
		for (int i = 0; i < num; i++)
		{
			if (a[num] <= a[i])
			dp[num] = max(dp[num], dp[i] + 1);
		}
		ans = max(ans, dp[num]);
		int flag = 0;
		for (int i = 0; i < c.size(); i++)
		{
			if (c[i] >= a[num])
			{
				flag = 1;
				c[i] = a[num];
				break;
			}
		}
		if (flag == 0)c.push_back(a[num]);
		num++;
	}
	cout << ans << endl;
	cout << c.size() << endl;
	return;
}

我们用一个 vector来存放最长不上升子序列,当前数若比vector的所有数小就进行覆盖,若大则加进vector,这样子操作的话vector的长度就会是我们所需子序列的个数,提交之后发现还是只有100,只能说这道题对时间复杂度卡的太死了,继续优化,这个时候可以根据Dilworth 定理进行推断:

狄尔沃斯定理亦称偏序集分解定理,该定理断言:对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。此定理的对偶形式亦真,它断言:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目。

得到如下代码:

void solve1()
{
	int ta = 0, x, tb = 0;
	while (cin >> x)
	{
		int s = 0;
		for (int i = 0; i < ta; i++)
		{
			if (a[i] < x)
			{
				a[i] = x;
				s = 1;
				break;
			}
		}
		if (s == 0)a[ta++] = x;
		s = 0;
		for (int i = 0; i < tb; i++)
		{
			if (b[i] >= x)
			{
				b[i] = x;
				s = 1;
				break;
			}
		}
		if (s == 0)b[tb++] = x;
	}
	cout << ta << endl << tb << endl;
	return;
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值