Description
CXT Poker More and more advanced, this time the number of cards can also be negative, this time cxt ready to the poker group, he intends to all the cards into a number of piles, each pile of the sum of the card and more than 0. Since poker is arranged sequentially, a stack of cards must be contiguous in the original heap. Please help CXT calculate how many different schemes exist for the distribution of cards. As the answer can be large, the output answer is divided by the remainder of 1,000,000,009.
Input Format
First line: Single integer: n,1≤n≤10^6
Line two to n + 1: In line i + 1 there is an integer: Ai, which represents the value of the first card.
Output Format
First line: A single integer that represents the remainder of the number of grouping schemes divided by 1,000,000,009
Sample Input
423-31
Sample Output
4
Hint
respectively [2 3−3 1], [2 3−3] [1], [2] [3−3 1], [2] [3−3] [1]
Note: Incorrect title description is not positive or negative
1. Pure DP O (n^2)
The pure DP method is very simple, dp[i] represents the first number of sub-methods. The condition of the state transition equation is dp[i] = Sigma (Dp[j]) J is 0<= J < I and Presum[j]<=presum[i]
The latter guarantees [j+1,i] that the sum of this paragraph is greater than or equal to 0
PS: A wrong DP strategy is that if num[i]>=0 and Num[i]+num[i-1] >=0 dp[i] = 2*dp[i-1]. Because for the last paragraph of each division of the former i-1, it can be thought that num[i] is put in or not. This is wrong, because the addition of the number of numbers in the first part of each division will be re-assembled. A paragraph that was originally negative may become positive
The code is as follows:
#include <iostream>#include<cstdlib>#include<cstdio>#include<cstring>#defineINF 1000000009using namespacestd;int*nums;int*sums;unsignedint*DP;intMainintargcChar Const*argv[]) { intN Cin>>N; //Dynamic ArraysNums =New int[n+5]; Sums=New int[n+5]; DP=NewUnsignedint[n+5]; //Input Initializationmemset (Sums,0,sizeof(int) * (n+5)); for(inti =1; I <= N; ++i) {scanf ("%d",&Nums[i]); Sums[i]= sums[i-1] +Nums[i]; } dp[0] =1; for(inti =1; I <= N; ++i) {Dp[i]=0; for(intj =0; J < I; ++J)if(sums[i]-sums[j]>=0)//represents a j+1 to I and an integer that can be a{Dp[i]+=Dp[j]; Dp[i]%= INF;//easy to write wrong}} cout<<dp[n]% INF <<Endl; Delete[] nums; Delete[] sums; Delete[] DP; return 0;}
O (n^2)
2.DP + sort de-rename tree array optimization O (NLGN)
O (n^2) will time out, the most important reason is that each inner layer loops to find a smaller presum[j than presum[i] and then overlay dp[j]. Want to optimize this process can consider first sort presum[], and because the same presum value, the subsequent presum corresponding DP value can be calculated according to the previous Presum DP value, so you can go heavy. It might be a little better to write a procedure out of the way, for example.
Like what
5
2 3-5 2 1
Nums:2 3-5 2 1
Original Presum:2 5 0 2 3
Sort presum:0 2 2 3 5
Go to Heavy uqsum:0 2 3 5 Length 4
The subscript of the tree array C starts from 1 to 4
Suppose there is a DP array, and this array dpk is different from the dp[k in O (n^2), where the dpk refers to the
The following uses DPK to represent the DP in this algorithm; DP[K] Represents the DP in the previous algorithm
Make tmpsum = uqsum[k-1] "The prefix of K (subscript k-1) in Uqsum and"
The total number of sub-methods when current and is tmpsum
For example, DP1 represents the current and for 0 hours of the number of laws; DP2 represents how many of the current and 2-hour laws there are ....
Note If duplicate current and uqsum[k-1] dpk represent all of the cumulative descriptions of Step5 such as
Associating a C array with a DP array according to the rules of the tree array, so that both the update and the lookup will become faster.
C1 = DP1
C2 = DP1+DP2
C3 = Dp3
C4 = dp1+dp2+dp3+dp4
According to the definition of the successor node: the successor of the C1 is C2, the successor of the C2 is the successor of the C4,C3 is C4
According to the definition of the precursor node: the precursor of C3 is that C2 other nodes have no precursor node
Every time a node of a tree array is updated, it is recycled to its successor node
Each time a node of a tree array is acquired, the and (from the following example) is cycled to find the first node of its predecessor.
The above understanding of the tree-like array is derived from: http://www.cnblogs.com/xudong-bupt/p/3484080.html
-----------------------------------------
#####
STEP1: set all the negative prefixes and the 0 prefix and the DP value to 1, this example does not have a negative prefix and
Before this step
dp:0 0 0 0
After this step
Dp:1 0 0 0
The corresponding
C:1 1 0 1//So we just need to update the c1+1 so that the successor node updates update (c1,1)
#####
STEP2: get the first current and Cursum = 0 + num[1] = 2//Because the presum of this time is already sorted and cannot be used, the original prefix must be reconstructed and
To the uqsum array to find a few than 2 small, found that there are 1, it corresponds to the number of DP1 before the cursum=2 and the sum of the numbers and corresponding is DP2 (comparison around, looking back will be better)
(This is the reason why you can go to heavy because each update is in the same position in the previous phase + =)
So DP2 + = (DP1 + DP2)
At this point DP is
Dp:1 1 0 0
The operation of the corresponding tree array is: Update (2,getsum (C2)) allows the successors of C2 and C2 to be added to the previous stage of C2, so thereafter
C2 + = C2; C4+=C2;
C:1 2 0 2
#####
Step3: Add a second number Cursum = 0 + num[1] + num[2] = 5
In Uqsum found there are 3 smaller than 5, they correspond to DP1,DP2,DP3 5 corresponds to IS DP4
So dp4 + = (dp1 + DP2 + dp3 + dp4)
At this time dp:1 1 0 2
The corresponding tree array operation is: Update (4,getsum (4))
C4 + = C4
So c:1 2 0 4
#####
STEP4: Add a third number cursum = 0 + n1+n2+n3 = 0
Found in Uqsum 0 smaller than 0, so just let dp1 + = (DP1) can
() The DP1 refers to the number of minutes of the last current and 0.
DP: 2 1 0 2//Note the meaning of the first 2 is the first time current and is 0 is dp[0]=1, plus the second time is 0 of dp[3] = 1
corresponding Update (1,getsum (1))
C1 + = C1
C for: 2 3 0 5
#####
Step5: Add fourth Number cursum = 0 + n1+n2+n3+n4 = 2
At this time again go to UQ inside find than 2 small discovery has 1 corresponds dp1 oneself is DP2
The DP2 that is not updated at this time refers to the DP2 in the last Step2, so DP2 + = (DP1+DP2)
This is a good illustration of Step4: dp1=2 's role because it records two times the current and 0 of the cumulative situation, so +DP1 has two effects
The first effect is from num[1] to num[4] This whole as a division because dp[0]=0
The second effect is from num[4] to num[4] This number as a paragraph, before as a section of the Division method because dp[3]=0
At this point the DP is: 2 4 0 2
The operation of the corresponding tree-like array is
C2 + = C2; C4+=C2;
Update (2,getsum (2))
At this point C is: 2 6 0 8
#####
Step6: Add last number cursum = 0 +n1+n2+n3+n4+n5 = 3
Go to Uqsum to find a smaller than 3 there are 2 respectively corresponding to DP1 DP2 plus the dp3 of the previous stage
So the result is res = DP1+DP2+DP3 at this time the output results exit.
The value of the tree array is res = Getsum (3);
Although c3 = Dp3 but because C3 is a precursor node C2
So Getsum (3) = C3 +c2 = dp3 + (DP1 + DP2) = 0 + 6
The final result is 6
------------------------------------
Summarize the process of DP change
0 2 3 5: This is uqsum.
--------
0 0 0 0
1 0 0 0
1 1 0 0
1 1 0 2
2 1 0 2
2 4 0 2
Final output 2+4+0
Summarize the process of C change
0 2 3 5: This is uqsum.
----------
0 0 0 0
1 1 0 1
1 2 0 2
1 2 0 4
2 3 0 5
2 6 0 8
Final output 6+0
The reason why the speed is faster is that the addition of C is much less than the number of the addition operations of DP
The code is as follows:
#include <iostream>#include<algorithm>using namespacestd;intnums[100005] ={0};//Storing raw dataintpresum[100005] ={0};//prefix and later sortintuqsum[100005] ={0};//sort and remove the heavy prefixes andintCNT =0;//indicates the length of the UQintc[100005] ={0};//tree-like array storage DPConst intMOD =1000000009; inlineintLowbit (intCID) { returnCID & (-CID);} InlineintGetsum (intCID) {//get the value of the node whose ID is the CID in the tree array intsum =0; for(inti = CID; I >=1; I-= Lowbit (i))//Note I's update is to find the precursor nodesum = (sum + c[i])%MOD; returnsum;} InlinevoidUpdateintCidintValue) {//Update the value of a c[cid] value is also taken from C, so it's already a couple of DP's . for(inti = CID; I <= CNT; i + =lowbit (i)) C[i]= (C[i] + value)%MOD;} InlineintFindintKey) {//Find (key) +1 means that the number of uqsum is smaller than key +1 is exactly the corresponding CID in C returnLower_bound (Uqsum,uqsum+cnt,key)-uqsum;//Lower_bound Returns the last pointer of uqsum small to CNT}intMainintargcChar Const*argv[]) { //enter data and compute both original prefixes and arrays intN Cin>>N; presum[0]=0; for(inti =1; I <= N; ++i) {cin>>Nums[i]; Presum[i]= presum[i-1] +Nums[i]; } //for Presum sort note the length of the presum is n+1Sort (presum,presum+n+1); //to rejoin the uqsum.uqsum[cnt]= presum[0];//because presum[0] may be negative for(inti =1; I < n+1; ++i) {if(Presum[i]! =uqsum[cnt]) uqsum[++CNT] =Presum[i]; } CNT++;//CNT Representation number//Initialize the C arrayUpdate (FIND (0)+1,1);//if the prefix and no negative number: in fact, the meaning of dp1=1 refers to the prefix and the uqsum[0] of the sub-method is 1//If there is a negative number in the prefix and: DP1 = dp2...= dpk = 1 where uqsum[k-1] = 0 intres =0;//record each DP and, for the next stage of updating intCursum =0; for(inti =1; I <= N; ++i)//for each prefix and{cursum+=Nums[i]; intCID = Find (cursum) +1;//get the current and corresponding CIDres = getsum (CID);//Update (cid,res);// } return 0;}
tree-like array
"Algorithmic Learning Notes" 40. Dynamic planning of tree array SJTU OJ 1289 Poker Group