zoukankan      html  css  js  c++  java
  • BZOJ4241 历史研究

    Description

    IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记。JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件。
    日记中记录了连续N天发生的时间,大约每天发生一件。
    事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。
    JOI教授决定用如下的方法分析这些日记:
    1. 选择日记中连续的一些天作为分析的时间段
    2. 事件种类t的重要度为t*(这段时间内重要度为t的事件数)
    3. 计算出所有事件种类的重要度,输出其中的最大值
    现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。

    Input

    第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
    接下来一行N个空格分隔的整数X1...XN,Xi表示第i天发生的事件的种类
    接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。

    Output

    输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度

    Sample Input

    5 5
    9 8 7 8 9
    1 2
    3 4
    4 4
    1 4
    2 4

    Sample Output

    9
    8
    8
    16
    16

    HINT

    1<=N<=10^5

    1<=Q<=10^5

    1<=Xi<=10^9 (1<=i<=N)

     

    正解:分块

    解题报告:

      这道题卡了我好久。。。数据恶心,差评。。。

      w[i][j]表示第i块到第j块的答案(即题目要求的最大值),cnt[i][j]表示前i块种类为j的数的个数前缀和。

      显然这可以O(N^(3/2))预处理。查询的时候整块的直接以整块答案为初值,然后考虑“边角余料”,加进num中统计,更新答案,具体看代码吧。

      我开始WA了,因为有一个数组没开long long。。。之后一直TLE,我不知道一个评测80s的题目TLE几次是什么感觉。。。经过二分查错,我发现并没有问题。

      最后迷之AC了,因为把一个不必要的long long开成了int就AC了。常数害死人。。。

      

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MAXN = 101111;
    21 const int kk = 1001;
    22 int n,m;
    23 int belong[MAXN],L[MAXN],R[MAXN];
    24 int num[MAXN];
    25 int match[MAXN],Stack[MAXN],top;
    26 LL w[kk][kk];
    27 int cnt[kk][MAXN];//w[i][j]表示第i块到第j块的答案, cnt[i][j]表示前i块数字为j的个数
    28 LL ans;
    29 
    30 struct node{
    31     int val,id;
    32 }a[MAXN];
    33 
    34 inline int getint()
    35 {
    36        int w=0,q=0;
    37        char c=getchar();
    38        while((c<'0' || c>'9') && c!='-') c=getchar();
    39        if (c=='-')  q=1, c=getchar();
    40        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    41        return q ? -w : w;
    42 }
    43 
    44 inline bool cmp(node q,node qq){ return q.val<qq.val; } 
    45 inline LL max(LL x,LL y){ if(x<y) return y; return x; }
    46 
    47 inline void work(){
    48     n=getint(); m=getint(); int block=sqrt(n),kuai;
    49     //int block=325; int kuai;
    50     kuai=(n-1)/block+1;    
    51     for(int i=1;i<=n;i++) a[i].val=getint(),a[i].id=i;
    52     for(int i=1;i<=n;i++) {    
    53     belong[i]=(i-1)/block+1;
    54     if(!L[belong[i]]) L[belong[i]]=i;
    55     R[belong[i]]=i;
    56     }
    57     sort(a+1,a+n+1,cmp); match[a[1].id]=1;
    58     //用每个数字出现的第一个位置代替这个数字作为它的编号
    59     for(int i=2;i<=n;i++) {//构出从小到大的原来顺序的离散化结果
    60     if(a[i].val==a[i-1].val) match[a[i].id]=match[a[i-1].id];
    61     else match[a[i].id]=i;
    62     }    
    63     for(int i=1;i<=n;i++) cnt[belong[i]][match[i]]++;
    64     for(int i=1;i<=kuai;i++) for(int j=1;j<=n;j++) cnt[i][j]+=cnt[i-1][j];//构前缀和
    65     for(int i=1;i<=kuai;i++) {
    66     memset(num,0,sizeof(num)); ans=0;
    67     for(int now=L[i];now<=n;now++) {//按原先的顺序统计种类的个数
    68         num[match[now]]++; ans=max(ans,(LL)num[match[now]]*a[match[now]].val);            
    69         if(now==R[belong[now]]) w[i][belong[now]]=ans;//已经到最后一个
    70     }    
    71     }
    72     memset(num,0,sizeof(num));
    73     int l,r;
    74     for(int o=1;o<=m;o++) {
    75     l=getint(); r=getint(); ans=0;
    76     if(belong[l]==belong[r]) {
    77         top=0;
    78         for(int i=l;i<=r;i++) { if(!num[match[i]]) Stack[++top]=match[i]; num[match[i]]++; ans=max(ans,(LL)num[match[i]]*a[match[i]].val); }
    79         //我们记录一个处理过的种类,Stack保存需要清零的对象
    80         while(top>0) num[Stack[top--]]=0;
    81     }
    82     else{
    83         top=0; if(belong[l]<belong[r]) ans=w[belong[l]+1][belong[r]-1];
    84         //找到不完整的块中的出现的种类,然后统计完整的块中的出现的次数
    85         for(int i=l;i<=R[belong[l]];i++) if(!num[match[i]]) num[match[i]]=cnt[belong[r]-1][match[i]]-cnt[belong[l]][match[i]],Stack[++top]=match[i];
    86         for(int i=L[belong[r]];i<=r;i++) if(!num[match[i]]) num[match[i]]=cnt[belong[r]-1][match[i]]-cnt[belong[l]][match[i]],Stack[++top]=match[i];
    87         for(int i=l;i<=R[belong[l]];i++) num[match[i]]++;
    88         for(int i=L[belong[r]];i<=r;i++) num[match[i]]++;
    89         while(top>0) { ans=max(ans,(LL)num[Stack[top]]*a[Stack[top]].val); num[Stack[top--]]=0;}//清零        
    90     }
    91     printf("%lld
    ",ans);
    92     }
    93 }
    94 
    95 int main()
    96 {
    97   work();
    98   return 0;
    99 }
  • 相关阅读:
    元组类型
    字符串类型
    列表类型
    python 循环
    python语句
    python运算符
    python1
    软件管理
    rpm yum
    LVM
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5719582.html
Copyright © 2011-2022 走看看