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.
原文地址:https://www.cnblogs.com/bobble/p/6846922.html