zoukankan      html  css  js  c++  java
  • poj 3368 Frequent values -Sparse-Table

    Time Limit: 2000MS   Memory Limit: 65536K
    Total Submissions: 16537   Accepted: 5981

    Description

    You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.

    Input

    The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line contains n integers a1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}) separated by spaces. You can assume that for each i ∈ {1, ..., n-1}: ai ≤ ai+1. The following q lines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the
    query.

    The last test case is followed by a line containing a single 0.

    Output

    For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.

    Sample Input

    10 3
    -1 -1 1 1 1 1 3 10 10 10
    2 3
    1 10
    5 10
    0

    Sample Output

    1
    4
    3

    Source


      先讲一下题目大意,给出一个有n个数的不下降数列,和q个问题每个问题是求[a,b]中出现次数最多的数出现的次数,

    有多组测试数据,当n = 0时测试结束

      方法有多种,第一种直接暴力枚举,就不讲了

      第二种用线段树,很多时候都不是完整的区间,怎么查?

      左右两端不完整区间连续的个数是可以求出来的,这个就比较简单,记录一下每个区间开始的位置

    ,然后再弄个数组,记录第i个数属于的区间的新编号,如果a不是一个短的开始就就用下一个区间的

    开始减去a (就把编号 + 1就是下一个区间的编号),结束部分就基本一样了

      中间完整的区间就交给线段树查,最好是

      把一个区间当成长度为1的线段,建树,查的时候就对应这个编号就行了。

    由于我不想写,所以就不给代码了,可以在网上查查

     

      第三种使用RMQ,反正又不会更新,再比较查询的时间复杂度,线段树的查询是O(log2N),而ST算法的查询时间O(1)(自行忽略

    log函数执行的时间或者打表的时间),线段树建树的时间复杂度貌似是O(2N)左右(大约实际有效的节点是原数组的2

    倍),ST算法的预处理时间是O(nlog2n)看起来差不多

      ST算法的思路和上面差不多,两端单独处理,中间交给ST算法去查。

    另外:

      1.用位运算时一定要加上括号,位运算优先级很低,之前没在意,RE了几次

      2.每次完成一轮计算该清0的清0,该还原的还原

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<cmath>
     5 using namespace std;
     6 typedef class MyData{
     7     private:
     8         MyData(int from,int end,int _count):from(from),end(end),_count(_count){}
     9     public:
    10         int from;
    11         int end;
    12         int _count;
    13         MyData(){}
    14         static MyData getNULL(){
    15             return MyData(0,0,0);
    16         }
    17 }MyData;
    18 vector<MyData> list;
    19 int a = -1000000,b;
    20 int *pos;
    21 int count1;
    22 int f[100001][20];
    23 int t;
    24 int n,q;
    25 void init(){
    26     const int limit = list.size();
    27     for(int i = 0;i < limit;i++)
    28         f[i][0] = list[i]._count;
    29     for(int j = 1; (1 << j) < limit;j++){
    30         t = 1 << j;
    31         for(int i = 0; i < limit && (i + t) < limit; i++){
    32             f[i][j] = max(f[i][j - 1], f[ i + (1 <<  j - 1) ][j - 1]);  //位运算优先级低!!!打括号
    33         }
    34     }
    35 }
    36 int main(){
    37     while(true){
    38         scanf("%d",&n);
    39         if(n == 0) break;
    40         scanf("%d",&q);
    41         pos = new int[(const int)(n + 1)];
    42         for(int i = 1;i <= n;i++){
    43             scanf("%d",&b);
    44             if(a == b){
    45                 list[list.size() - 1]._count++;
    46                 pos[i] = pos[i - 1];
    47             }else{
    48                 if(!list.empty())
    49                     list[list.size() - 1].end = i - 1;
    50                 list.push_back(MyData::getNULL());
    51                 pos[i] = count1++;
    52                 list[list.size() - 1].from = i;
    53                 list[list.size() - 1]._count = 1;
    54             }
    55             a = b;
    56         }
    57         list[list.size() - 1].end = n;
    58         init();
    59         for(int i = 1;i <= q;i++){
    60             scanf("%d%d",&a,&b);
    61             if(pos[a] == pos[b]){
    62                 printf("%d
    ",b - a + 1);
    63                 continue;
    64             }
    65             if(pos[b] - pos[a] == 1){
    66                 int result = max(list[pos[a]].end - a + 1,b - list[pos[b]].from + 1);
    67                 printf("%d
    ",result);
    68                 continue;
    69             }
    70             int ans = 0;
    71             ans = max(list[pos[a]].end-a+1,b-list[pos[b]].from+1);
    72             b = pos[b] - 1;
    73             a = pos[a] + 1;
    74             int k = (int)(log((double)b-a+1.0)/log(2.0));
    75             int t2 = max(f[a][k],f[b-(1<<k)+1][k]);
    76             ans = max(ans,t2);
    77             printf("%d
    ",ans);
    78         }
    79         delete[] pos;
    80         list.clear();
    81         count1 = 0;
    82         a = -1000000;
    83     }
    84     return 0;
    85 }

    [后记]

      附赠调试这道题时所用的对拍器、比较程序和数据生成器

    cmp.cpp:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 char buf1[1000];
     6 char buf2[1000];
     7 FILE *fin1;
     8 FILE *fin2;
     9 int main(int argc, char* argv[]){
    10     fin1 = fopen(argv[1],"r");
    11     fin2 = fopen(argv[2],"r");
    12     while(!(feof(fin1))&&!(feof(fin2))){
    13         fscanf(fin1,"%s",buf1);
    14         fscanf(fin2,"%s",buf2);
    15         if(strcmp(buf1, buf2) != 0)    return 1;
    16     }
    17     if(feof(fin1) != feof(fin2)) return 1;
    18     return 0;
    19 }

    md_fv.cpp:

    #include<iostream>
    #include<fstream>
    #include<cstdlib>
    #include<time.h>
    using namespace std;
    ofstream fout("fv.in");
    int main(){
        
        srand((unsigned)time(NULL));
        
        int n = rand()%100 + 1;
        int q = rand()%100 + 1;
        
        fout<<n<<" "<<q<<endl;
        
        int start = rand()%1000 - 500;
        for(int i =1; i<= n;i++){
            start += rand()%2;
            fout<<start<<" ";
        }
        
        fout<<endl;
        for(int i = 0;i < q;i++){
            start = rand()%n + 1;
            int end = min(rand()%(n - start + 1) + start,n);
            fout<<start<<" "<<end<<endl;
        }
        
        fout<<"0"<<endl;
        return 0;
    }

    test_fv.cpp:

     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<time.h>
     4 using namespace std;
     5 typedef bool boolean;
     6 int statu;
     7 boolean aFlag;
     8 int main(){
     9     system("g++ fv.cpp -o fv.exe");
    10     system("g++ cmp.cpp -o cmp.exe");
    11     system("g++ md_fv.cpp -o md_fv.exe");
    12     system("g++ std.fv.cpp -o std.fv.exe");
    13     for(int i = 0;i < 1000;i++){
    14         aFlag = true;
    15         system("md_fv");
    16         system("std.fv");
    17         clock_t begin = clock();
    18         statu = system("fv");
    19         clock_t end = clock();
    20         cout<<"测试数据#"<<i<<":"; 
    21         if(statu != 0){
    22             cout<<"RuntimeError";
    23         }else if(system("cmp fv1.out fv.out") != 0){
    24             cout<<"WrongAnswer";
    25         }else{
    26             cout<<"Accepted";
    27             aFlag = false;
    28         }
    29         cout<<"		Time:"<<(end - begin)<<"ms"<<endl;
    30         if(aFlag){
    31             system("pause");
    32         } 
    33     }
    34     return 0;
    35 }
  • 相关阅读:
    hadoop streaming 中跑python程序,自定义模块的导入
    许久未更新~~重启~~
    什么叫共轭先验或者共轭分布?
    Call for Papers International Conference for Smart Health (ICSH) 2014
    IEEE/ACM International Conference on Advances in Social Network Analysis and Mining (ASONAM) 2014 Industry Track Call for Papers
    linux 查看文件方法
    Double 保留小数点后N位
    java获取当前日期所在的周的周一,并以周一为一周开始
    Core Data Programming Guid
    UIDatePicker应用 常用属性和方法
  • 原文地址:https://www.cnblogs.com/yyf0309/p/5676751.html
Copyright © 2011-2022 走看看