問題描述: |
yep有很多收藏品,爲的是以後有機會送給它鍾愛的女性朋友,每到假期它都會去收集各式 各樣的收藏品,面對琳琅滿目的收藏品有時候它都不知道如何下手。但爲了女生它一般還是 會勇於獻出自己的錢包…… 又到了七夕,yep又該開始準備禮物了,禮物當然是從它所有的收藏品中選取,它有很多很 多件收藏品,但其中不乏重複的收藏,女生收到禮物時是不喜歡看見同種禮物的,要不然會 被視爲湊數,被發現的後果很嚴重,yep會被狠狠地X掉。yep的收藏品是以其價值度來區分 的,即同種的收藏的價值度相同,不同的收藏品價值度不同。價值度數字越小表明這個收藏 品越好。 但是由於yep的懶惰,買好後的收藏品它從沒整理過,於是它們都堆在了一個箱子裏面,每 次從箱子中只能拿出一件收藏品,而且拿出一件收藏品必須要把堆在它上面的所有收藏品都 搗出來,所有的收藏品都按先後順序一個一個壘在箱子裏面。 可沒等到七夕那天,女生竟然提前拜訪!當時yep還沒整理出它要送的禮物呢…………當女 生看到那個箱子的時候,她不禁皺起了眉頭,她說:“爲了懲罰你這個懶蛋,我要對你送我 的禮物再提出要求。首先,你要送我一個收藏品,你必須也要送給我這件收藏品底下緊挨着 的收藏品,除非它是最底下的一個。否則就不能再送我禮物了,因爲你只有一次機會;其 次,你要送給我價值度爲I的收藏就一定要送給我價值爲I-1的收藏品;最後,你必須送給我 儘可能多的收藏品。“ 面對這個情形,yep心急如焚。幸好它平時有記錄自己都買了哪些收藏品,根據記錄它就可 以選擇要送給她的收藏了…… 現在給你它的記錄,請你幫它挑選…… |
|
數據輸入: |
本題目每個測試點有T組數據。 第一行輸入一個T,表示數據組數,對於每組數據: 接下來T組數據: 第一行一個整數n,表示yep擁有的收藏品個數; 第二行n個數,按順序表示yep的每件收藏品的價值度,第i個讀入的收藏品的位置編號爲i。 (價值度均不大於N) |
|
結果輸出: |
每組數據只有一行。 如果有解,輸出兩個數max和ans,用一個空格隔開。 max表示yep送給女生的收藏品個數;ans表示它送給她的第一件收藏最早的可能的位置編 號。 如果無解,輸出一個0即可。 |
|
樣例: |
6 4 4 3 2 1 4 2 1 2 3 4 3 3 2 1 4 2 1 1 3 4 3 2 4 1 4 2 1 4 2 |
4 1 3 2 3 2 2 1 4 1 2 1 |
核心思想: |
經過簡化之後本題的意思是:在一串數中找出連續的一段K個數,它們恰好組成1~K的一個 排列,輸出最大的K以及這個數段第一個數的位置(如果有多個段符合條件,輸出最靠前 的)。 數據的範圍爲100000,考慮有O(nlogn)或O(n)兩種算法時間複雜度。這裏採用的是基本 O(n)的算法。 由於數段要符合1~K的排列,所以不可能出現兩個一樣的數。用數組b[I]記錄當前數字I所在 的位置,即a[b[I]]=I。用一個變量start表示當前數段的第一個數的位置,初始賦成1。從第一 個數開始掃描,當遇到一個以前已經出現的數,即b[a[I]]<>0。此時再繼續掃描已經沒有意 義,因爲已經有重複的數了,必須先處理原來的數,更新最優解,之後刪除原來b[a[I]]及之 前的所有數,因爲更新最優解後b[a[I]]之前的數(包括它自己)都沒有用了。之後把start更 新爲b[a[I]]+1(這個b[a[I]]還是原來的數,並沒有更新),之後再把b[a[I]]的值更新爲I。依次 枚舉直到全部掃描完,最後再更新一次。 之後的問題是如何更新最優解了,用l、r表示當前數段的左座標和右座標。首先如果b[1]=0 表示當前數段內沒有1,肯定無解;其次,要保證K=r-l+1。於是可以枚舉K,數段長度最少 是2,最長是I(當時第一層循環枚舉到的數)-start。直到b[K]=0,或者退出循環,如果b[K]在 區間[l,r]之外則更新[l,r],如果K=r-l+1那麼表示此時[l,r]之間恰好是1~r-l+1的排列,更新最 優解,並記錄數段起始位置。 此算法枚舉數時間複雜度O(n),刪除數複雜度O(n),不確定因素唯有第二層循環枚舉K的 量,只能因數據而異,但實際上由於如果b[a[I]]=0那麼直接更新b[a[I]]而不會進入循環,頻繁 進入循環勢必不會枚舉過多量,枚舉很多量要建立在之前很長時間沒有進入第二層的循環基 礎之上,所以複雜度不會過高,但不排除有使本算法退化成O(n^2)的數據,限於本人數學水 平有限,不會進行嚴謹的證明,時間分析姑且寫到這裏。 空間複雜度O(n) 題解這麼強大絕對不是我寫的,而且程序會更強大,各位扶好坐好。 |
{
The problem is to find a number K that you can find K collections in a row
which they are exactly a permutation of 1..K.
}
program yepcollection; //Written by UCHIHA.TMTK.INU at 2009.4.1 0:00
var
a:array[0..200001]of longint; //a[i] means the ith collection.
b:array[0..200001]of longint; //b[i] means the current number of the collection which the value is i.
i,t:longint;
procedure work;
var
i,j,n:longint;
ans,max:longint; //ans,max are what the problem description said.
start,temp:longint; //start means the current line's first number and the collections before it are useless;temp means temp.....
procedure update(h:longint);//to update the ans and the max
var
i:longint;
l,r:longint;
now:longint;//the current legal max value
begin
l:=b[1]; r:=b[1]; //l,r means the left edge and the right edge number
now:=1;
if l=0 then exit; //if b[1]=0 then exit...because the most valuable collection is needed.
if (now=(r-l+1))and((now>max)or((now=max)and(ans>l)))then begin
max:=now;
ans:=l;
end;
for i:=2 to h-start do begin //to find the max,and the max is only can be chosen from 2 to h-start
if b[i]=0 then break;
inc(now);
if r<b[i] then r:=b[i]
else if b[i]<l then l:=b[i];
if (now=(r-l+1))and((now>max)or((now=max)and(ans>l)))then begin
max:=now;
ans:=l;
end;
end;
end;
begin
start:=1;
max:=0; ans:=0;
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
readln(n);
for i:=1 to n do begin
read(a[i]);
if b[a[i]]=0 then b[a[i]]:=i
else begin //Because every value we can only have one collection,when we find two,we should deal with them.
update(i);
temp:=b[a[i]];
for j:=start to b[a[i]] do b[a[j]]:=0;
start:=temp+1;
b[a[i]]:=i;
end;
end;
update(n+1);
if max<>0 then writeln(max,' ',ans) else writeln(0);
end;
begin
assign(input,'yepcollection.in');
reset(input);
assign(output,'yepcollection.out');
rewrite(output);
readln(t);
for i:=1 to t do work;
close(output);
close(input);
end.
題目來源:NDK 1368