zoukankan      html  css  js  c++  java
  • [线段树][数学] Jzoj P4237 Melancholy

    Description

    DX3906星系,Melancholy星上,我在勘测这里的地质情况。
    我把这些天来已探测到的区域分为N组,并用二元组(D,V)对每一组进行标记:其中D为区域的相对距离,V为内部地质元素的相对丰富程度。
    在我的日程安排表上有Q项指派的计划。每项计划的形式是类似的,都是“对相对距离D在[L,R]之间的区域进行进一步的勘测,并在其中有次序地挑出K块区域的样本进行研究。”采集这K块的样品后,接下来在实验中,它们的研究价值即为这K块区域地质相对丰富程度V的乘积。
    我对这Q项计划都进行了评估:一项计划的评估值P为所有可能选取情况的研究价值之和。
    但是由于仪器的原因,在一次勘测中,这其中V最小的区域永远不会被选取。
    现在我只想知道这Q项计划的评估值对2^32取模后的值,特殊地,如果没有K块区域可供选择,评估值为0。
     

    Input

    第一行给出两个整数,区域数N与计划数Q。
    第二行给出N个整数,代表每一块区域的相对距离D。
    第三行给出N个整数,代表每一块区域的内部地质元素的相对丰富程度V。
    接下来的Q行,每一行3个整数,代表相对距离的限制L,R,以及选取的块数K。

    Output

    输出包括Q行,每一行一个整数,代表这项计划的评估值对2^32取模后的值。
     

    Sample Input

    5 3
    5 4 7 2 6
    1 4 5 3 2
    6 7 1
    2 6 2
    1 8 3

    Sample Output

    5
    52
    924
     

    Data Constraint

    题解

    • 题目大意:有n个区间每个区间有一个相对距离D和矿值为V,每次询问相对距离在[l...r]中的选k个矿值的乘积之和(矿值最小的不选)
    • K=1
    • 显然,就是线段树区间查询就好了,就是V值之和-V值的最小值,只用维护区间和和区间最小值就好了
    • K=2
    • 貌似也不难,可以先计算没有减去最小V值的答案,那么只用记录一段区间和和最小值,然后先预处理出前缀和,然后根据这些其实就很容易推到答案
    • K=3、4、5、6
    • 本蒟蒻就不想推了,可以考虑也是线段树,维护一段区间取K个的乘积之和
    • 那么考虑一下对于两个区间怎么去合并,那么如果现在两个区间中一共要取k个
    • 那么是不是我们就要枚举两个区间内分别选多少个,然后可以将其乘起来p[i]=x[j]*y[i-j]/p[i]=x[j]*y[i-j-1]*y[7](代表的是当前的V值)
    • 这样的话我们就解决了区间合并的问题,那么剩下的就是线段树的维护就好了

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #define N 100010
     6 using namespace std;
     7 int n,Q,l,r,k;
     8 unsigned int f[N*4][7],g[7],jc[7],p[7];
     9 struct edge{ int d,v; }a[N];
    10 bool cmp(edge a,edge b) { return a.d<b.d; }
    11 void work(unsigned int*x,unsigned int*y,unsigned int*k)
    12 {
    13     if (x[7]>y[7]) swap(x,y);
    14     if (!x[7]) for (int i=0;i<=7;i++) k[i]=y[i];
    15     else
    16     {
    17         memset(p,0,sizeof(p)),p[0]=1;
    18         for (int i=1;i<=6;i++)
    19         {
    20             for (int j=0;j<=i;j++) p[i]+=x[j]*y[i-j];
    21             for (int j=0;j<i;j++) p[i]+=x[j]*y[i-j-1]*y[7];
    22         }
    23         p[7]=x[7]; for (int i=0;i<=7;i++) k[i]=p[i];
    24     }
    25 } 
    26 void build(int d,int l,int r)
    27 {
    28     f[d][0]=1;
    29     if (l==r) { f[d][7]=a[l].v; return; }
    30     int mid=l+r>>1;
    31     build(d*2,l,mid),build(d*2+1,mid+1,r),work(f[d*2],f[d*2+1],f[d]);
    32 }
    33 void Query(int d,int l,int r,int L,int R)
    34 {
    35     if (a[l].d>R||a[r].d<L) return;
    36     if (L<=a[l].d&&a[r].d<=R) { work(f[d],g,g); return; }
    37     int mid=l+r>>1;
    38     Query(d*2,l,mid,L,R),Query(d*2+1,mid+1,r,L,R);
    39 }
    40 int main()
    41 {
    42     scanf("%d%d",&n,&Q);
    43     for (int i=1;i<=n;i++) scanf("%d",&a[i].d);
    44     for (int i=1;i<=n;i++) scanf("%d",&a[i].v);
    45     jc[0]=1; for (int i=1;i<=6;i++) jc[i]=jc[i-1]*i;
    46     sort(a+1,a+n+1,cmp),build(1,1,n);
    47     while (Q--) scanf("%d%d%d",&l,&r,&k),memset(g,0,sizeof(g)),g[0]=1,Query(1,1,n,l,r),printf("%lld
    ",g[k]*jc[k]);
    48 }
  • 相关阅读:
    【经典数据结构】B树与B+树
    【经典算法】线性时间排序
    【经典算法】归并排序
    【经典算法】快速排序
    python模块之shelve
    python模块之pickle
    python模块之json
    python之序列化
    python模块之shutil和zipfile
    python模块之sys
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10331534.html
Copyright © 2011-2022 走看看