越往后学,你就越会知道,数学不好带来的苦痛与折磨。
这第二题要是不会数学没个做啊(大哭
第一问我本来想用动态规划做,但是感觉会爆。。毕竟六位数,n^2的时间复杂度。有人想用a[i][j]表示从i到j的递减数长度最大值,最后再逐次比较a[i][j]的大小……
哈哈哈,应该可行。但是还是nlogn的时间复杂度比较好啊。直接递减数列找然后二分的方法!简单而容易理解!!!耗时也少!妙哉,妙哉。
第二问等价于求一个最长递增数列。有人给出了证明,但我没怎么看懂,潸然泪下啊。
#include<iostream>
#include<memory.h>
#include<cstdio>
using namespace std;
int main()
{
int a[100005]; int i=0,mid,r;
while (scanf("%d", &a[i++]) != EOF)continue;
i--;
int f[100000] = { 1000000 };//f[0]得取一个大一点的数,不然可能比a[j]小。。就循环不了啦。
int ans = 0, ans2 = 0;
for (int j = 0; j <= i; j++)
{
if (f[ans] >= a[j])
{
f[++ans] = a[j]; //递减数列的创建过程
}
else
{
int p = 1; r = ans;
while (p < r) {
mid = (p + r) / 2;
if (f[mid] >= a[i])p = mid + 1;
else {
r = mid;
}
}
if (p != 1)f[p] = a[i];
} //二分查找新的数在递减数列中的位置,并替换原来的数
}
cout << ans << endl;
memset(f, 0, sizeof(f)); //这里我本来想开一个新数组g[100001]的,奈何vs报错,估计是空间不够了
for (int j = 0; j <= i; j++)
{
if (f[ans2] <= a[j])
{
f[++ans2] = a[j];
}
else
{
int p = 1; r = ans2;
while (p < r) {
mid = (p + r) / 2;
if (f[mid] < a[i])p = mid + 1;
else {
r = mid;
}
}
f[p] = a[i];
}
}
cout << ans2;
system("pause");
return 0;
}
ok,写完了,我复习(yuxi)微积分去了。
1.2考试,菜鸡落泪