牛客网的:
比赛的时候好不容易写出了转移方程,可能是因为一点步数的原因卡了很久,也把题目读了很多遍。
其实就是每个点都达到最优,然后我们的策略有,买或者不买。
emmm... 动态规划 在每个地方停下来都是最优的。
但是步数有点小问题,这个要想明白,我的代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<set>
using namespace std;
typedef long long ll;
ll a[100005];
ll dp[3][100005];
ll s[3][100005];
int main() {
ll t; cin >> t; while (t--) {
ll n; cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
//不买的话,可能不卖,或者是把上一个给卖了
dp[0][1] = 0; s[0][1] = 0;
dp[1][1] = -a[1]; s[1][1] = 1;//买了的
//dp[2][1] = 0;
for (int i = 2; i <= n; i++) {
//if (a[i] == 0) {
// dp[0][i] = dp[0][i - 1];
// dp[1][i] = dp[1][i - 1];
// s[1][i] = s[1][i - 1];
// s[0][i] = s[0][i - 1];
// continue;
//}
dp[0][i] = max(dp[0][i - 1], dp[1][i - 1] + a[i]);// , dp[2][i - 1]);
dp[1][i] = max(dp[0][i - 1] - a[i], dp[1][i - 1]);
//dp[2][i] = dp[1][i - 1] + a[i];
//卖了的话
//cout << "没买"<<dp[0][i] << endl;
//cout <<"买了"<< dp[1][i] << endl;
//cout << "卖了" << dp[2][i] << endl;
if (max(dp[0][i - 1], dp[1][i - 1] + a[i]) == dp[0][i - 1]) {
s[0][i] = s[0][i - 1];//没买 就是上个没买
}
else if (max(dp[0][i - 1], dp[1][i - 1] + a[i]) == dp[1][i - 1] + a[i]) {
s[0][i] = s[1][i - 1] + 1;
}
if (max(dp[0][i - 1] - a[i], dp[1][i - 1]) == (dp[1][i - 1])) {
s[1][i] = s[1][i - 1];
}
else if (max(dp[0][i - 1] - a[i], dp[1][i - 1]) == (dp[0][i - 1] - a[i]))
{
s[1][i] = s[0][i - 1] + 1;
}
//cout <<" 没买" << s[0][i-1] << endl;
//cout << "买了"<<s[1][i - 1] << endl;
}
//s[1][i] = s[0][i - 1] + 1;//买了 就是以前的加一
//买了的话,可能..??
cout << dp[0][n] << " "<<s[0][n]<<endl;
}
return 0;
}
应该是这个吧...
反正最重要的是下面这两行
(因为想取最小的 所以+1放在后面 就这一点卡了10%的数据啊啊)
然后 ,有的人这么写 、
不知道谁的 截个图表示尊敬。。。 反正下面这样分类也可以啦
_(:з」∠)_ 洛谷的界面也很舒服啊 但是一想到初中生高中生就有点不舒服。。。。
问题在哪里呢,其实上面那个题,只要看它是不是一直下降
一直上升着,上升着,下降了的时候就把它卖出去。这样就简单了呢
同样 洛谷这个导弹拦截系统 我就没用dp
其实它只是一个 最长上升子序列问题 就很简单了
但我想的 每个状态只能用一次 然后在任何一个状态停下来。
都能用吧 然后第二问还没A(待补充)
https://blog.csdn.net/fsahfgsadhsakndas/article/details/57918879
#include<iostream>
#include<algorithm>
#include<string>
#include<set>
#include<cstdio>
using namespace std;
typedef long long ll;
struct node {
int a;
int s;
} node[100005];
int main() {
int aa;
int n = 0;
int kk = 10;
while (scanf("%d", &node[++n].a) != EOF)
continue;
//这里因为最后一行也++n了 只是没读到东西
n--;
node[0].a = 50005;
node[0].s = 0;
int record = 0;
//其实我的strut 完全可以用两个数组代替..
for (int i = 1; i <= n; i++) {
record = 0;
for (int j = 0; j < i; j++) {// j是用于检验的,从前往后所有的..
// cout << node[j].a<<" " << node[i].a <<" "<< node[i].s <<" "<< node[j].s;
if ((node[j].a >= node[i].a) && (node[j].s >= record)) {
node[i].a = node[i].a;
record = node[j].s;
}
node[i].s = record + 1;
}
//【果然对我而言这里非常容易错】
//i j这里错的 ,然后要先看自己的程序再..
//cout << i <<" "<< node[i].a <<" "<< node[i].s << endl;
}
int temp = 0;
//这里其实可以直接优化的 ...
for (int i = 1; i <= n; i++) {
temp = max(temp, node[i].s);
}
cout << temp << endl;
int cnt;
int maxx = 0;
int ans = 0;
int c[100005]; int j;
for (int i = 1; i <= n; i++) {
for ( j = 1; j <= ans; j++) {
if (c[j] >= node[i].a) {
//ans++;
c[j] = node[i].a;
break;
//这里可以直接 用c[ans++]=node[i].a代替什么的
}
//我们要平等.. 怎么判断它开了
//j是开了链子的数目啊啊啊啊....
//如果找得到,只要能连就连上,因为其他的如果大于它,顺序在后面只能开新的
//如果找不到,也只能开新的
//.. 顺序是多么重要啊
}
if(j>ans)
{
ans++;
c[ans] = node[i].a;
}
}
cout << ans << endl;
return 0;
}