12.29 洛谷1020 導彈攔截(尋找最長遞減/增數列)
阿新 • • 發佈:2018-12-31
越往後學,你就越會知道,數學不好帶來的苦痛與折磨。
這第二題要是不會數學沒個做啊(大哭
第一問我本來想用動態規劃做,但是感覺會爆。。畢竟六位數,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考試,菜雞落淚