赞
踩
思路:
这其实是一道数学题(最开始一直在枚举,服啦)
我们的目的是求最大利润
当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来出售
还可以参考我觉得挺好的一篇题解:
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;
- }
思路:
采用双指针,一个指向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;
- }
还有一篇动态规划的题解我感觉也不错
代码奉上:
- 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;
- }
思路:
令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;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。