• luogu P2344 奶牛抗议 DP 树状数组 离散化


    P2344 奶牛抗议

    最新讨论

    • 暂时没有讨论

    题目背景

    Generic Cow Protests, 2011 Feb

    题目描述

    约翰家的N 头奶牛正在排队游行抗议。一些奶牛情绪激动,约翰测算下来,排在第i 位的奶牛的理智度为Ai,数字可正可负。

    约翰希望奶牛在抗议时保持理性,为此,他打算将这条队伍分割成几个小组,每个抗议小组的理智度之和必须大于或等于零。奶牛的队伍已经固定了前后顺序,所以不能交换它们的位置,所以分在一个小组里的奶牛必须是连续位置的。除此之外,分组多少组,每组分多少奶牛,都没有限制。

    约翰想知道有多少种分组的方案,由于答案可能很大,只要输出答案除以1000000009 的余数即可。

    输入输出格式

    输入格式:

    • 第一行:单个整数N,1 ≤ N ≤ 100000

    • 第二行到第N + 1 行:第i + 1 行有一个整数Ai,−10^5 ≤ Ai ≤ 10^5

    输出格式:

    单个整数:表示分组方案数模1000000009 的余数

    输入输出样例

    输入样例#1:
    4
    2
    3
    -3
    1
    输出样例#1:
    4

    说明

    解释:如果分两组,可以把前三头分在一组,或把后三头分在一组;如果分三组,可以把中间两头分在一组,第一和最后一头奶牛自成一组;最后一种分法是把四头奶牛分在同一组里。

    Solution

    用f[i]表示前I头cows的分组方案数,很容易得到DP方程:

    边界

    然后sum部分可以用前缀和维护,朴素的DP 大约是所以会TLE两个CASES  

     1 const p=1000000009;
     2 var
     3    n,i,j:longint;
     4    a,s,f:array[0..100000] of longint;
     5 
     6 function sum(i,j:longint):longint;
     7 begin
     8   exit(s[j]-s[i]);
     9 end;
    10 
    11 procedure add(var app:longint; aa:longint);
    12 begin
    13   app:=((app mod p)+(aa mod p)) mod p;
    14 end;
    15 
    16 begin
    17     readln(n);
    18     for i:= 1 to n do
    19     begin
    20       readln(a[i]);
    21       s[i]:=s[i-1]+a[i];
    22     end;
    23 
    24     f[0]:=1;
    25     for i:= 1 to n do
    26      for j:= 0 to i-1 do
    27         if sum(j,i)>=0 then add(f[i],f[j]);
    28 
    29     writeln(f[n]);
    30 end.

    于是我们要优化哇,对状态转移方程移项可得:

    可见求f[i]时,如果前面的sum[j-1]小于等于sum[i]就把他对应的f[j]加到f[i]里

    所以我们可以用树状数组维护,用sum作为tree的下标表示tree[b]表示当前情况下sum=b的对应的分组种数

    因为sum=b可能会超级大,于是我们可以离散

    离散,就是计算出第i个前缀和的排第几小存在f[i]里面,双字段qsort实现,因为要保证后面的循环查询更新按照顺序

    但是要注意边界和负数情况,我们首先将Sum=0加入同时更新边界即 add(f[1],1)

    然后循环不断查询tree[1..sum[i]]的区间和便得到了此时的f[i]存到ans, 并更新

    那么时间复杂度大概是

     1 program w;
     2 const
     3   p=1000000009;
     4 
     5 var
     6    n,i,ans:longint;
     7    sum,a,rk,f,tree:array[0..100000] of longint;
     8 
     9 function lowbit(app:longint):longint;
    10 begin
    11     exit(app and -app);
    12 end;
    13 
    14 procedure add(ii,x:longint);
    15 begin
    16   while ii<=n do
    17    begin
    18      tree[ii]:=(tree[ii]+x) mod p;
    19      ii:=ii+lowbit(ii);
    20    end;
    21 end;
    22 
    23 function get(aa:longint):longint;
    24 begin
    25   get:=0;
    26   while aa>0 do
    27   begin
    28       get:=(get+tree[aa]) mod p;
    29       aa:=aa-lowbit(aa);
    30   end;
    31 end;
    32 
    33 procedure qsort(l,r: longint);
    34   //注意一定要双字段
    35 var
    36   i,j,x,y,z: longint;
    37 begin
    38   i:=l;  j:=r;  x:=sum[(l+r) div 2];  z:=rk[(l+r) div 2];
    39   repeat
    40     while (sum[i]<x) or ((sum[i]=x) and (rk[i]<z)) do inc(i);
    41     while (x<sum[j]) or ((sum[j]=x) and (rk[j]>z)) do dec(j); 
    42     if not(i>j) then
    43     begin
    44       y:=sum[i]; sum[i]:=sum[j];  sum[j]:=y;
    45       y:=rk[i]; rk[i]:=rk[j];  rk[j]:=y;
    46       inc(i);  j:=j-1;
    47     end;
    48   until i>j;
    49   if l<j then qsort(l,j);
    50   if i<r then qsort(i,r);
    51 end;
    52 
    53 begin
    54   readln(n);
    55   for i:= 1 to n do
    56     readln(a[i]);
    57 
    58   n:=n+1;  sum[1]:=0;  rk[1]:=1;
    59   for i:= 2 to n do
    60   begin
    61    sum[i]:=sum[i-1]+a[i-1];
    62    rk[i]:=i;
    63   end;
    64 
    65   qsort(1,n);
    66 
    67   for i:= 1 to n do
    68     f[rk[i]]:=i;
    69 
    70   add(f[1],1);   //处理边界
    71   for i:= 2 to n do  //循环到i ,得出来的ans便是f[i]的值
    72   begin
    73       ans:=get(f[i]);
    74       add(f[i],ans);
    75   end;
    76 
    77   writeln(ans);
    78 end.
  • 相关阅读:
    世界黑客怎么排名?曝郭盛华公司30万美元收购海外域名,怎么回事
    AI应该享有与动物一样的权利吗?
    2020年将会迎来人工智能新浪潮,哪些商业巨头已经提前布局好了?
    揭秘郭盛华的真实收入,事实和你想的真不一样
    Excel表格中单击一个单元格如何将整行整列变色
    ldconfig与 /etc/ld.so.conf
    在excel中,应用公式到多行
    Excel怎么把两个单元格中的文字合并到一个单元格中
    在EXCEL中批量添加超链接
    windows中对文件进行排序
  • 原文地址:https://www.cnblogs.com/bobble/p/6846922.html
Copyright © 2020-2023  润新知