• [分治] Jzoj P5807 简单的区间


    Description

     

    Input

    第一行两个正整数 n 和 k 。
    第二行包含 n 个正整数,第 i 个正整数表示 ai。

    Output

    一行一个正整数,表示答案。
     

    Sample Input

    【样例 1 输入】
    4 3
    1 2 3 4
    【样例 2 输入】
    4 2
    4 4 7 4

    Sample Output

    【样例 1 输出】
    3
    【样例 2 输出】
    6
     

    Data Constraint

    对于 30% 的数据,n ≤ 3000;
    对于另外 20% 的数据,数列 a 为随机生成;
    对于 100% 的数据,1 ≤ n ≤ 3 × 10^5 , 1 ≤ k ≤ 10^6 , 1 ≤ ai ≤ 10^9。

    题解

    • 考虑分治
    • 我们可以暴力求出二分的右端区间,然后暴力求出sum,mid+1~i的最大值
    • 然后考虑左区间的合法数量,可以记录一个d[i][0/1]表示在[l,r]区间里i出现过的次数,和有没有越过mid
    • 最后就求出d数组,更新答案

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 using namespace std;
     7 int n,k,tot,a[300010],d[1000010][2],pos[300010],mx[300010],sum[300010];
     8 long long ans;
     9 void doit(int l,int r)
    10 {
    11     if (l==r) return;
    12     int mid=(l+r)>>1;
    13     tot=sum[mid]=mx[0]=0;
    14     for (int i=mid+1;i<=r;i++)
    15     {
    16         if (a[i]>a[mx[tot]]) mx[++tot]=i;
    17         sum[i]=(sum[i-1]+a[i]%k)%k;
    18         d[(sum[i]-a[mx[tot]]%k+k)%k][0]++;
    19         pos[i]=mx[tot];
    20     }
    21     mx[tot+1]=r+1;
    22     int p=1,k1=mid+1,mxl=0,suml=0;
    23     for (int i=mid;i>=l;i--)
    24     {
    25         suml=(suml+a[i]%k)%k;
    26         mxl=max(mxl,a[i]);
    27         while (p<=tot&&a[mx[p]]<=mxl) p++;
    28         while (k1<mx[p]) d[(sum[k1]-a[pos[k1]]%k+k)%k][0]--,d[sum[k1]][1]++,k1++;
    29         ans+=d[(k+mxl%k-suml)%k][1];
    30         if (p<=tot) ans+=d[(k-suml)%k][0];
    31     }
    32     for (int i=mid+1;i<k1;i++) d[sum[i]][1]--;
    33     for (int i=k1;i<=r;i++) d[(sum[i]-a[pos[i]]%k+k)%k][0]--;
    34     doit(l,mid),doit(mid+1,r);
    35 }
    36 int main()
    37 {
    38     //freopen("interval.in","r",stdin);
    39     //freopen("interval.out","w",stdout);
    40     scanf("%d%d",&n,&k);
    41     for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    42     doit(1,n);
    43     printf("%lld",ans);
    44     return 0;
    45 }
  • 相关阅读:
    Linux就该这么学28期——Day03 2.4-2.7
    Linux就该这么学28期——Day02 2.1-2.3
    Linux就该这么学28期——开篇
    层次遍历应用

    二叉树
    Linux 随手记录
    KMP算法详解(转)
    使用MySQL connector/C++链接MySQL数据库
    C++ 代码片段
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9470801.html
Copyright © 2020-2023  润新知