HDU 4869 Turn the pokers multi-school training first game 1009, hdupokers
Turn the pokers
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission (s): 282 Accepted Submission (s): 89
Problem DescriptionDuring summer vacation, Alice stay at home for a long time, with nothing to do. she went out and bought m pokers, tending to play poker. but she hated the traditional gameplay. she wants to change. she puts these pokers face down, she decided to flip poker n times, and each time she can flip Xi pokers. she wanted to know how to handle the results does she get. can you help her solve th Is problem?
InputThe input consists of multiple test cases.
Each test case begins with a line containing two non-negative integers n and m (0 <n, m <= 100000 ).
The next line contains n integers Xi (0 <= Xi <= m ).
OutputOutput the required answer modulo 1000000009 for each test case, one per line.
Sample Input
3 43 2 33 33 2 3
Sample Output
83HintFor the second example:0 express face down,1 express face upInitial state 000The first result:000->111->001->110The second result:000->111->100->011The third result:000->111->010->101So, there are three kinds of results(110,011,101)
AuthorFZU
Source2014 Multi-University Training Contest 1
Question
These days are the most annoying. The question "facing posture is not enough... The algorithm I used during the competition was: "O (NlgN) sorting-O (N) computing the answer range-O (N) summation of the answer ". But it's TLE... Later, I thought about it carefully. In fact, there is no need to sort it, and I can calculate the answer range by O (N. Then I re-wrote the part and struggled with the parity of bit operations for half a day.
I will talk about how my algorithms come from.
Abstraction
This model is very clever, because it is a card flip, then each card has two States (front '1' and back '0 ').
Can we abstract this actual example?
Of course!
First, introduce the Symbol M (n, k): indicates that among n cards, there are only all possible sets of k faces.
Next, I introduce a binary operation based on elements in M (n, k). The flip operation is represented by multiplication.
Why is binary calculation? We slowly consider the flip status. "Flip three from four cards ." Can this sentence be understood as "_ M (4, 0) * _ M (4, 3? I use a prefix underline to represent an element of this set. That is to say, this expression starts status transfer from the front. We do not consider the result for the moment. The state transfer method is to flip three sheets. In other words, a single Multiplication operation is equivalent to a cumulative flip. The first flip is 0, so all the answers are M (4, 0); the second flip is 3, so all the answers are M (4, 3 ). The sum of two flip operations is our answer.
Again, a single Multiplication operation is equivalent to a cumulative flip. Of course, multiple multiplication operations (for example, three first, two second, and finally three more) you can also view the accumulated flip for multiple times. That is, for a specific card, if it is flipped for an even number of times, it is equivalent to not flipped; if it is flipped for an odd number of times, it is equivalent to flipped once.
Then what is the scope of this operation? That's right. It's the whole of all the elements of the just-defined Symbol M (n, k), that is, G = {x | x ε M (n, k), k = 0, 1, 2, 3 ,..., n .}.
Next, we will focus on the nature of this operation: (for convenience, we will call this operation multiplication later)
Therefore, the operation * for G and the operation built on G is an Abel group (exchange group ).
However, this algebra system is obviously not good enough. We should continue to expand him.
In other words, we just studied the nature of the two elements to perform this operation. Now we are going to study the nature of the two sets to perform this operation. Of course, first we start with the results and try to find the rules.
For example, in this calculation: M (n, x1) * M (n, x2), to facilitate the analysis results, we suppose x1> = x2. What kind of results will it produce?
Return to the previous definition. M (n, x1) indicates there are y1: = x1 frontend and y2: = (n-x1) backend. The next step is to flip the two cards. Let's assume that it re-flip the card I flipped over the last time, and flip the card j never flipped over. In this way, there is a possibility of C (y1, I) + C (y2, j), and of course it must satisfy the formula of the number of combinations. What are the results generated here? Assume that there are z at the end, and y1 at the beginning. Reduce I at first and increase j at the end. Because I + j = x2, x1> = x2, there are x1-x2 <= z <= min (n, (n-x1) + (n-x2 )). Moreover, if you write a script on the draft, you will find that the original z = y1-I + j = x1-I + (x2-I) = x1 + x2-2 * I. That is, z is an arithmetic difference sequence with a tolerance of 2.
For ease of understanding, I introduced the addition symbol + to represent the parallel operation of the Set.
For example:
M (4, 3) * M (4, 2) = M (4, 1) + M (4, 3)
M (8, 5) * M (8, 3) = M (8, 2) + M (8, 4) + M (8, 6) + M (8, 3, 8)
M (8, 4) * M (8, 6) = M (8, 3) + M (8, 5) + M (8, 7)
I don't know if there is a rule, that is, the parity of the result sequence. If x1 and x2 are both an even number, the result is an odd number sequence. If the result is an odd number, the result is an even number sequence. If the result is an odd number, the result is an odd number sequence. There is another rule. If there are multiple multiplication operations, isn't it necessary to perform another Multiplication operation on each generated result? That's right. Strictly speaking, the introduction of addition also introduces the concept of allocation rate, which is equivalent to the establishment of a ring. However, it is not very useful, but it is easy to understand.
Return to the problem of multiple multiplication operations. If every Multiplication operation is performed, the answer will be very slow, because here it is equivalent to expanding the data of N to (N/2) A group of new data is exponential. For example, if I calculate this set of multiplication:
M (8, 4) * M (8, 6) * M (8, 3)
When the running result of the first multiplication is:
M (8, 4) * M (8, 6) = M (8, 3) + M (8, 5) + M (8, 7)
Next, go to multiply one by one:
M (8, 3) * M (8, 3) = M (8, 0) + M (8, 2) + M (8, 4) + M (8, 6)
M (8, 5) * M (8, 3) = M (8, 2) + M (8, 4) + M (8, 6) + M (8, 3, 8)
M (8, 7) * M (8, 3) = M (8, 4) + M (8, 6)
We can see that the actual answer is M (8, 4) * M (8, 6) * M (8, 3) = M (8, 0) + M (8, 2) + M (8, 4) + M (8, 6) + M (8, 8)
In other words, isn't it convenient if we record the upper and lower bounds? In this way, it will not be expanded layer by layer.
Therefore, the problem is abstracted to calculate the intervals of each layer and consider parity.
Calculate the interval and record parity
Each time I update the last answer interval. In fact, it is more accurate to check whether the range needs to be enlarged. In particular, it is used to determine whether the x (equivalent to k in M (n, k) in the preceding range) is not in this range, and the correct value assignment is enough, that is, low = 0, high = n. The rest determine the distance between the boundary of the current interval. One value is a small value and the other value is a vertex.
Of course, you can't forget to deal with parity. Parity and exclusive or operations are similar, so I use different or operations.
Finally, because it is a sequence with a tolerance of 2, we only record the range and parity. Therefore, the answer should be judged based on parity.
The overall time complexity is O (N) {calculation interval}-O (N) {calculation answer }.
Calculation of the combination number
The formula for calculating the number of combinations is simple. C (n, m) = n! /(M! * (N-m )!)
In the modulo operation, division a/B is equivalent to a * B ^-1, that is, multiplication of its inverse. So we can calculate the factorial of the inverse element in the pre-processing.
The definition of reverse element is that B that satisfies a * B % p = 1 is called the reverse element of a. Sometimes it is recorded as B = inv (). The calculation method is simple. Do you still remember to extend Euclidean? Ax + by = gcd (a, B ). Because the adjacent two numbers must be mutually unique, it can be written as ax + by = 1. This indefinite equation can be transformed from a linear homogeneous equation with a single element. Therefore, we can quickly obtain the inverse element by extending Euclidean. Of course, it can also be calculated directly through recursive solutions.
After the inverse element is calculated, it is the query result. This is to note that the modulo is required for each multiplication.
Sample Code
/*************************************** **************************************** Copyright notice * Copyright (c) 2014 All rights reserved * ---- Stay Hungry Stay Foolish ---- ** @ author: Shen * @ name: HDU 4869 Turn the pokers * @ file: G: \ My Source Code \ [ACM] competition \ 0722-MUTC [1] \ I. cpp * @ date: 2014/07/22 13:52 * @ algorithm: group theory, number theory, combination *************************************** *********************************** * ***/# Include <cstdio> # include <iostream> # include <algorithm> using namespace std; template <class T> inline bool updateMin (T & a, T B) {return a> B? A = B, 1: 0;} template <class T> inline bool updateMax (T & a, T B) {return a <B? A = B, 1: 0;} typedef long int64; typedef pair <int, int> range; // The Answer range // first-> LowerBound, second-> UpperBoundconst int MaxM = 100005; const int64 MOD = 1000000009; int64 inv [MaxM]; // reverse element, a * inv (a) % p = 1int64 fac [MaxM]; // factorial, 1*2*3 *... int64 rfc [MaxM]; // inverse factorial, inv (1) * inv (2) * inv (3) * ...int n, m; int x [MaxM]; void init () {inv [0] = inv [1] = 1; fac [0] = fac [1] = 1; rfc [0] = rfc [1] = 1; for (int I = 2; I <MaxM; I ++) {inv [I] = (MOD-MOD/I) * inv [MOD % I]) % MOD; fac [I] = (fac [I-1] * I) % MOD; rfc [I] = (rfc [I-1] * inv [I]) % MOD ;}} inline int64 c (int64 n, int64 k) {return (fac [n] * rfc [k] % MOD) * rfc [n-k] % MOD;} inline bool cmp (int a, int B) {return a> B;} range update (int x, range & cur, bool & isOdd) {int low = 0, high = 0; int curl = cur. first, curh = cur. second; // Update IsOdd) isOdd ^ = (x % 2 = 1); // update Lower Bound if (curl <= x & x <= curh) low = 0; else low = min (abs (curl-x), abs (curh-x); // update Upper Bound x = n-x; if (curl <= x & x <= curh) high = n; else high = max (n-abs (curl-x ), n-abs (curh-x); return make_pair (low, high);} void solve () {for (int I = 0; I <m; I ++) scanf ("% d", & x [I]); range res = make_pair (0, 1); bool isO Dd = 0; for (int I = 0; I <m; I ++) res = update (x [I], res, isOdd); int64 ans = 0; for (int I = res. first; I <= res. second; I ++) if (I % 2 = 1) = isOdd) ans = (ans + c (n, I) % MOD; cout <ans <endl;} int main () {init (); while (~ Scanf ("% d", & m, & n) solve (); return 0 ;}