zoukankan      html  css  js  c++  java
  • hdu 3303 Harmony Forever (线段树 + 抽屉原理)

    http://acm.hdu.edu.cn/showproblem.php?pid=3303

    Harmony Forever

    Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 813    Accepted Submission(s): 222

    Problem 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 , Y<=500000 .
    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

    题解:

    很显然的线段树问题,但是这个题有点技巧就是利用抽屉原理来降低复杂度。

    什么是抽屉原理?抽屉原理也叫鸽巢原理,鸽巢原理就是给定N+1个数,则必定至少有两个数Mod(N)的余数是相同的! 假设要求的MOD是Y,则首先查找[0,Y-1]区间的最小值,因为这样的区间不会有两个数的余数相同,记录下结果。然后依次查找[Y,Y+Y-1],[Y+Y,Y+Y+Y-1]。。。。等区间,每个区间都会找出一个最小值,将这些最小值对Y进行取模,得到最小值!

     

    这题还要注意:范围较小的时候直接查找,否则TLE。

     

    代码:

      1 #include<iostream>
      2 #include<stdio.h>
      3 #include<algorithm>
      4 #include<string.h>
      5 #include<vector>
      6 
      7 using namespace std;
      8 #define N 500000
      9 #define INF 100000000
     10 vector<int> vct;
     11 
     12 struct Nod
     13 {
     14     int l,r,mins;
     15 }node[(N<<2)+10];
     16 
     17 int maxInput;
     18 int posArray[N+10];
     19 
     20 void building(int l,int r,int p)
     21 {
     22     node[p].l = l;
     23     node[p].r = r;
     24     node[p].mins = INF;
     25     if(l==r)    return ;
     26     int mid = (l+r)>>1;
     27     building(l,mid,p<<1);
     28     building(mid+1,r,p<<1|1);
     29 }
     30 
     31 void update(int x,int p)
     32 {
     33     if(node[p].l>x||node[p].r<x)    return;
     34     if(node[p].l == node[p].r&&node[p].l==x)
     35     {
     36         node[p].mins = x;
     37         return;
     38     }
     39     update(x,p<<1);
     40     update(x,p<<1|1);
     41     node[p].mins = min(node[p<<1].mins,node[p<<1|1].mins);
     42 }
     43 /**RE的查询方式
     44 
     45 int query(int l,int r,int p)  //找[l,r]区间的最小值
     46 {
     47     if(node[p].l == l && node[p].r == r)  return node[p].mins;
     48     int mid = (node[p].l+node[p].r)>>1;
     49     if(r<=mid)  return query(l,r,p<<1);
     50     else if(mid>l)  return query(l,r,p<<1|1);
     51     else return min(query(l,mid,p<<1),query(mid+1,r,p<<1|1));
     52 }
     53 
     54 */
     55 int Query(int l,int r,int index)//找[l,r]区间的最小值
     56 {
     57     if(node[index].l>r || node[index].r<l) return INF;
     58     if(node[index].l>=l && node[index].r<=r) return node[index].mins;
     59     if(node[index].l < node[index].r)
     60         return min(Query(l,r,index<<1),Query(l,r,index<<1|1));
     61     return INF;
     62 }
     63 
     64 int search(int y)
     65 {
     66     int minAns = INF,id = 0,i;
     67     for(i=vct.size()-1;i>=0;i--)
     68     {
     69         if(vct[i]%y== 0) return i+1;
     70         if(vct[i]%y<minAns)
     71         {
     72             minAns = vct[i]%y;
     73             id = i+1;
     74         }
     75     }
     76     return id;
     77 }
     78 
     79 int solve(int y)  //抽屉原理
     80 {
     81     int l=0,r=y-1,minAns=INF,id,temp;
     82     while(l<=maxInput)
     83     {
     84         if(maxInput<r)  r=N;
     85         temp = Query(l,r,1);
     86         if(temp!=INF)
     87         {
     88             if(temp%y<minAns)
     89             {
     90                 minAns = temp%y;
     91                 id = posArray[temp];
     92             }
     93             else if(temp%y == minAns && posArray[temp] > id)
     94             {
     95                 id = posArray[temp];
     96             }
     97         }
     98         l+=y;
     99         r+=y;
    100     }
    101     return id;
    102 }
    103 
    104 int main()
    105 {
    106     int t,cas=1;
    107     while(~scanf("%d",&t)&&t)
    108     {
    109         building(0,N,1);
    110         char op[5];
    111         maxInput = 0;
    112         vct.clear();
    113         if(cas!=1) printf("
    ");
    114         printf("Case %d:
    ",cas++);
    115         while(t--)
    116         {
    117             scanf("%s",op);
    118             if(op[0]=='B')
    119             {
    120                 int x;
    121                 scanf("%d",&x);
    122                 if(maxInput<x)  maxInput = x;
    123                 vct.push_back(x);
    124                 posArray[x] = vct.size();
    125                 update(x,1);
    126             }
    127             else if(op[0]=='A')
    128             {
    129                 int y;
    130                 scanf("%d",&y);
    131                 if(vct.size()==0)   puts("-1");
    132                 else if(y<=5000)    printf("%d
    ",search(y));   //防超时
    133                 else printf("%d
    ",solve(y));
    134             }
    135         }
    136     }
    137     return 0;
    138 }
  • 相关阅读:
    day27_递归
    Linux常用命令
    Linux中的标准输入输出文件
    秋招日记《三》——字节三面挂
    《秋招日记》阿里一面
    秋招日记<->PDD一面挂
    十大排序
    第 254 场周赛 数组元素的最小非零乘积
    找不到boost/bind.hpp
    如何在Google浏览器中批量下载网页上的图片
  • 原文地址:https://www.cnblogs.com/crazyapple/p/3224660.html
Copyright © 2011-2022 走看看