翻譯:有一個整數序列a[],你需要将它劃分成兩個非空序列,滿足兩個序列都是等差數列。"等差數列"定義為相鄰兩項間內插補點相等的非空序列;特别地,長度為1或2的序列也是等差數列,但長度為0的不是(因為必須非空)。"劃分"定義為,将原序列中的所有元素分成兩個序列,滿足每個元素都在恰好一個序列中,且保留其在原序列中的順序。例如[1, 3, 4]和[2, 5]就是[1, 2, 3, 4, 5]的一個劃分,[1, 2, 3]和[4, 5]也是,但[1, 2]和[3, 4]不是(不全),[2, 1]和[3, 4, 5]也不是(順序不對)。
輸入格式:第一行一個正整數n,第二行n( 2 ≤ n ≤ 30000)個用空格分隔的整數,表示序列a( - 108 ≤ ai ≤ 108),且序列中沒有重複的元素。
輸出格式:假如不存在這樣的方案,輸出"No solution"(不含引号);否則,輸出兩行,每行描述劃分出的一個等差序列。如果有多個方案,輸出任意一個。
樣例輸入1:
6
4 1 2 7 3 10
樣例輸出1:
1 2 3
4 7 10
思考過程:很好的貪心題,首先,考試的時候并沒有做出來這個題,考完以後,開始搜題解,并沒有搜到,于是陷入思考,想了半天,寫了個暴力,16個點大資料T掉了。
沒辦法,直接看的别人的送出記錄,看了一下别人的代碼,恍然大悟。
題解:因為題目中說要構造兩個等差數列,而且順序還不能變,是以第一個元素一定在某一個序列的開頭,明确這一點後考慮,先确定一個數列,生成此數列為等差數列,然後在把剩下的數按順序加入到第二個序列當中,判斷是否為等差數列。生成第一個等差數列可以用公差相等處理,現在已知确定兩個數就一定可以計算出。在兩個等差數列的公差中,其中一個的公差是固定的,比如說 原序列為{a1,a2,a3,a4,a5} ,那麼考慮生成序列的公差,隻可能是a2-a1 a3-a2, a3-a1 三個當中的一種,因為無論怎麼選,隻要選3個,至少有兩個在同一個序列當中(抽屜原理)。是以就可以枚舉三個公差,判斷可行性。有了第一個序列的公差,很容易生成出第一個序列(要生成到不能再生成),那剩下的一定就是第二個數列。但是,每一次維護第一個序列不一定能找到最優解,比如9 12 0 5 10 15 20 25 30,如果按以上的操作進行,會生成9 12 15 和 0 5 10 20 25 30顯然這不是最優解。現在考慮在生成第一個數列以後,第二個數列不滿足條件時,如何去調整方案。在調整的時候要注意,不能破壞第一個數列的等差數列的合法性,是以就枚舉删除第一個數列的末尾元素,插入到第二個數列中,判斷是否等差,直到數列一被删空。關于維護第二個數列是否等差, 可以記錄每個數的位置,用map暴力記錄公差。
successful hack
12
0 6 12 18 23 24 25 26 27 28 29 30
#,include <bits/stdc++.h>
using namespace std;
int a[30010], n;
bool vis[30010];
void print(vector <int> v){
for(int i = 0; i < v.size(); i ++) printf("%d ", v[i]);
printf("\n");
}
bool check(vector <int> v){
if(!v.size()) return false;
if(v.size() == 1 || v.size() == 2) return true;
int d = v[1] - v[0];
for(int i = 2; i < v.size(); i ++) if(v[i] - v[i-1] != d) return false;
return true;
}
bool solve(int l, int r){
vector <int> v1, v2;
for(int i = 1; i <= n; i ++) vis[i] = 0;
int d = a[r] - a[l];
int last = -1, get = a[l];
for(int i = 1; i <= n; i ++)
if(a[i] == get) get += d, v1.push_back(a[i]), last = i;
else vis[i] = 1;
for(int i = 1; i <= n; i ++) if(vis[i]) v2.push_back(a[i]);
if(check(v2)){print(v1),print(v2); return true;}
vis[last] = 1, v1.pop_back(), v2.clear();
for(int i = 1; i <= n; i ++) if(vis[i]) v2.push_back(a[i]);
if(check(v2)){print(v1),print(v2);return true;}
return false;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
if(n == 2) printf("%d\n%d", a[1], a[2]);
else if(!solve(1,2) && !solve(2,3) && !solve(1,3)) printf("No solution");
return 0;
}