poj 3145 Harmony Forever


Description

We believe that every inhabitant of this universe eventually will find a way to live together in harmony and peace; that trust, patience, kindness and loyalty will exist between every living being of this earth; people will find a way to appreciate and cooperate with each other instead of continuous bickering, arguing and fighting. Harmony — the stage of society so many people dream of and yet it seems so far away from now…

Fortunately, the method of unlocking the key to true Harmony is just discovered by a group of philosophers. It is recorded on a strange meteorite which has just hit the earth. You need to decipher the true meaning behind those seemingly random symbols… More precisely, you are to write a program which will support the following two kinds of operation on an initially empty set S:

  1. B X: Add number X to set S. The Kth command in the form of B X always happens at time K, and number X does not belong to set S before this operation.
  2. A Y : Of all the numbers in set S currently, find the one which has the minimum remainder when divided by Y. In case a tie occurs, you should choose the one which appeared latest in the input. Report the time when this element is inserted.

It is said that if the answer can be given in the minimum possible time, true Harmony can be achieved by human races. You task is to write a program to help us.

Input

There are multiple test cases in the input file. Each test case starts with one integer T where 1 ≤ T ≤ 40000. The following T lines each describe an operation, either in the form of “B X” or “A Y ” where 1 ≤ X ≤ 500 000, 1 ≤ Y ≤ 1 000 000.

T = 0 indicates the end of input file and should not be processed by your program.

Output

Print the result of each test case in the format as indicated in the sample output. For every line in the form of “A Y”, you should output one number, the requested number, on a new line; output -1 if no such number can be found. Separate the results of two successive inputs with one single blank line.

Sample Input

5
B 1
A 5
B 10
A 5
A 40
2
B 1
A 2
0

Sample Output

Case 1:
1
2
1

Case 2:
1

Source

 
題意:初始一個空集,定義B操作向空集中加入一個數,插入時間是集合中原有元素總數加一,A操作詢問集合中mod一個給定數結果最小的數的時間(取模相同的取最晚放入集合的元素)並輸出。
//=============================================================================================

題解:我們可以開一個x[i]大小的數組q,每一次插入的時候,更新這個數組中的每一個值,詢問的時候就直接輸出q[x[i]]即可。但這道題中x[i]的大小為50000,O(N²)的算法承受不了,那怎么辦呢?用分段的思想解決,開一個長度為MAX(x[i])的數組c,每插入一個數,就在數組c中標記已插入,詢問操作的時候分別查找1~x[i]-1,x[i]~2*x[i]-1,2*x[i]~3*x[i]-1, ……,k*x[i]~max(x[i]),這些段中取模值最小的數,時時更新答案。在查找段最小值的時候,可以利用樹狀數組或者線段樹兩種數據結構,把時間復雜度降到O(logMAX(x[i]))。但是,在x[i]很小的時候,時間復雜度就降到了O(N)(還有常數時間。。。)。所以只用線段樹也是過不了的。那么就綜合兩種算法的優點,每次詢問的時候,如果x[i]小於lim,則到q數組中直接輸出答案,大於lim的詢問進行分段查找,每次插入兩個數組q和c即可。然后調整一下lim的值,就可以有很好的時效表現了。

 

AC CODE

 

//我用的是樹狀數組的做法,常數小。(雖然依然很慢。。。)

 

program pku_3145;

const lim=1000;

      max=500000;    //在線做法把數組開到最大。。時間就定死了。。。

var q,c,a,t:array[1..max] of longint;

    i,tot,time,all,x:longint;

    command:char;

//============================================================================

procedure ins(x:longint);    //插入操作。

var j:longint;

begin

  inc(time); t[time]:=x; a[x]:=time;

  for j:=1 to lim do

    if q[j]=0 then q[j]:=time else

    if x mod j<=t[q[j]] mod j then q[j]:=time;

  j:=x;

  while j<=max do

  begin

    inc(c[j]);

    j:=j+j and (-j);

  end;

end;

//============================================================================

function ask(x:longint):longint;    //樹狀數組求前n項和。

begin ask:=0;

  while x>0 do

  begin

    inc(ask,c[x]);

    x:=x-x and (-x);

  end;

end;

//============================================================================

function askmin(be,en:longint):longint;    //查找每段的最小值。

var l,r,mid,pre,now:longint;

begin

  if be=0 then l:=1 else l:=be;

  if en>max then r:=max else r:=en;

  pre:=ask(l-1); askmin:=-1;

  repeat    //二分查找。

    mid:=(l+r) shr 1;

    now:=ask(mid);

    if now>pre then

    begin

      r:=mid-1;

      askmin:=mid;    //找到一個值才更新,改動左端點不更新。(這里困了好久T.T)

    end else l:=mid+1;

  until l>r;

end;

//============================================================================

procedure enquiry(x:longint);    //詢問操作。

var ans,l,r,k:longint;

begin

  if time=0 then writeln('-1') else    //空集輸出-1。

  if x<=lim then writeln(q[x]) else    //小的詢問直接輸出。

  begin

    ans:=x-1;

    l:=0; r:=x-1;    //分段。

    while l<=max do

    begin

      k:=askmin(l,r);

      if (k>0) and ((k mod x<ans mod x) or

      ((k mod x=ans mod x) and (a[k]>a[ans]))) then ans:=k;

      l:=l+x; r:=r+x;

    end; writeln(a[ans]);

  end;

end;

//============================================================================

begin

  while true do

  begin

    readln(tot); time:=0;

    if tot=0 then exit;

    inc(all); writeln('Case ',all,':');

    fillchar(q,sizeof(q),0);

    fillchar(c,sizeof(c),0);

    fillchar(a,sizeof(a),0);

    fillchar(t,sizeof(t),0);    //清除冗余數據。

    for i:=1 to tot do

    begin

      readln(command,x);

      if command='B' then ins(x) else enquiry(x);

    end; writeln;

  end;

end.


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com