• JZOJ.5231【NOIP2017模拟8.5】序列问题


    Description

     

    Input

    输入文件名为seq.in。
    首先输入n。
    接下来输入n个数,描述序列 A。

    Output

    输出文件名为seq.out。
    输出一行一个整数代表答案。
     

    Sample Input

    7
    0 35 40 45 56 65 94

    Sample Output

    66636
     

    Data Constraint

    对于30%的数据,n<=5000
    对于60%的数据,n<=50000
    对于100%的数据,n<=500000,0<=A[i]<=10^9

    ST加暴力枚举区间显然过不了,复杂度为O(n2)

    考虑分治。对于区间[l,r],我们可以轻易求得[l,mid]和[mid+1,r]的值,关键在于求$sum_{xin[l,\,mid],\,yin[mid+1,\,r]}f(x,\,y)*g(x,\,y)$

    我们可以先枚举右端点r,求得每个点i到mid+1的最大值和最小值max[i]和min[i],然后从mid开始右往左枚举每一个左端点j,求得min_l,max_l,然后可以求得右端点中从左到右的第一个大于max_l,第一个小于min_l,的位置i,如图所示(我们假设min的位置在max位置的左边)

    这样右边就被分成三段。

    对于第一段(mid-min之间),由于最大值和最小值都是max_l,min_l,所以右端点这一段的值就是min_l*max_l*(min-mid)

    对于第二段(min-max之间),由于最大值是max_l,最小值不定,不过我们可以把max_l提取出来,剩下的就是这段区间min_l的和了,所以我们可以用前缀和维护一下。smin[max-1]-smin[min-1]

    对于第三段(max-r之间),由于最大值最小值都是不定,但是它们都在mid的右边,我们在分治的时候就已经算好了,直接加上去就好了  。 spul[r]-spul[max-1]

    minmax右边同理。

     1 #include<iostream>
     2 #include<cstdio>
     3 #define qaq 1000000007
     4 using namespace std;
     5 const int N=500005;
     6 long long a[N],minn[N],maxx[N],sminn[N],smaxx[N],spul[N],ans;
     7 int n;
     8 void fz(long long l,long long r){
     9     if (r<l) return;
    10     if (l==r){
    11         ans=(ans+a[l]*a[r])%qaq;
    12         return;
    13     }
    14     long long mid=(l+r)>>1;
    15     fz(l,mid);
    16     fz(mid+1,r);
    17     minn[mid]=1e12;
    18     maxx[mid]=0;
    19     sminn[mid]=0;
    20     smaxx[mid]=0;
    21     spul[mid]=0;    
    22     for (int i=mid+1;i<=r;i++){
    23         if (a[i]>maxx[i-1]) maxx[i]=a[i];
    24         else maxx[i]=maxx[i-1];
    25         if (a[i]<minn[i-1]) minn[i]=a[i];
    26         else minn[i]=minn[i-1];
    27         sminn[i]=sminn[i-1]+minn[i];
    28         smaxx[i]=smaxx[i-1]+maxx[i];
    29         spul[i]=(spul[i-1]+maxx[i]*minn[i])%qaq;
    30     }
    31     long long mi=mid;
    32     long long ma=mid;
    33     long long mis=1e12;
    34     long long mas=0;
    35     for (int i=mid;i>=l;i--){
    36         if (a[i]<mis) mis=a[i];
    37         if (a[i]>mas) mas=a[i];
    38         while ((mi<r)&&(minn[mi+1]>=mis)) mi++;
    39         while ((ma<r)&&(maxx[ma+1]<=mas)) ma++;
    40         if (mi<ma)
    41         ans=(ans+mis%qaq*mas%qaq*(mi-mid)%qaq+(sminn[ma]-sminn[mi])%qaq*mas%qaq+(spul[r]-spul[ma])%qaq)%qaq;
    42         else 
    43         ans=(ans+mis%qaq*mas%qaq*(ma-mid)%qaq+(smaxx[mi]-smaxx[ma])%qaq*mis%qaq+(spul[r]-spul[mi])%qaq)%qaq;
    44     }
    45 }
    46 int main(){
    47     freopen("seq.in","r",stdin);
    48     freopen("seq.out","w",stdout);
    49     scanf("%d",&n);
    50     for (int i=1;i<=n;i++)
    51      scanf("%lld",&a[i]);
    52     ans=0;
    53     fz(1,n);
    54     printf("%lld
    ",ans);
    55     return 0;
    56 }
    神奇的代码

    乘的顺序很重要,乘的顺序很重要,乘的顺序很重要!!!(苦悲的ans那里乘的放到后面没有事先%%%就变负数waaaaaaaa了QAQ)

  • 相关阅读:
    Windows Power Shell
    一个自律的人有多可怕!
    Android之TextureView浅析
    BEGINNING SHAREPOINT&#174; 2013 DEVELOPMENT 第9章节--client对象模型和REST APIs概览 介绍SP2013中远程APIs
    敌兵布阵(线段树)
    kendo AutoComplete实现多筛选条件
    Android 65K问题之Multidex原理分析及NoClassDefFoundError的解决方法
    让我心碎的五道题
    输入一列数组,输出它的逆序数组
    centos下配置防火墙port失败
  • 原文地址:https://www.cnblogs.com/Lanly/p/7297380.html
Copyright © 2020-2023  润新知