Topics from NOIP2007TG3
If I'm in the examination room, I'm already having a break.
Today all day of the time to vote on this question, the harvest is not small.
First question.
Title Description
Description
"Problem description"
Handsome often play with classmates a matrix take number game: for a given n*m matrix, each element in the matrix AIJ
is a non-negative integer. The rules of the game are as follows:
1. Each fetch must take one element from each row, a total of n. After M times, all elements of the matrix are taken out;
2. Each element taken away can only be the beginning or end of the line where the element is located;
3. Each fetch has a score value, the sum of the scores for each row, the number of points per row = The element value taken away
Where I is the number of times I fetch (numbering starting from 1);
4. The end of the game must be divided into M-time score of the sum.
Handsome want to ask you to help write a program, for any matrix, you can find out the maximum score after the number.
Enter a description input
Description
1th Act two integers separated by spaces N and M.
The 2~n+1 behavior n*m Matrix, where each line has m a nonnegative integer separated by a single space.
outputs description output
Description
The output contains only 1 rows, an integer, which is the maximum score after the input matrix is taken.
sample input to
sample
2 3
1 2 3
3 4 2
Sample output Sample
outputs
82
data
size & Hint
Sample explanation
1th Time: Line 1th takes the beginning element, the 2nd row takes the tail element, this score is 1*21+2*21=6
2nd time: Both lines take the beginning of the element, the score is 2*22+3*22=20
3rd time: Score for 3*23+4*23=56. Must be divided into 6+20+56=82
Limit
60% of data meet: 1<=n, m<=30, answer not more than16
100% data satisfies: 1<=n, m<=80, 0<=aij<=1000
First read the question, we found that the row and row are independent of each other without interference, so that we can read a line of processing a row, each line is a separate problem, equivalent to the n set of data, to find out the sum of the answer.
So we dropped the space from N2 to N.
Then start thinking about it. It is not difficult to find that after taking part of the numbers, the remaining numbers always form an interval. Since the number of taken away is known, the remaining numbers are also known in the Order of weights, resulting in an interval DP, similar to a stone merge. It satisfies the optimal substructure and satisfies no-no-effect.
Using F[i][j] to represent the optimal solution of interval [I, j], there are two methods
F[I][J] = max (A[i] + 2 * f[i+1][j], a[j] + 2 * f[i][j-1]);//weighted value of direct calculation f[i][j] = max (a[i]*2^ (m-j+i) + f[i+1][j], a[j]*2^ ( M-j+i) + f[i][j-1])//double-doubling each time
The first, is to do a second power of the square table, direct calculation, very good understanding.
The second, is also more convenient one, only need to multiply the small interval by two, the principle of multiplication distribution law is applied. After the whole interval, the interval length of the small multiplication of the number of times, the final effect is the power of the second side. It should not be difficult to understand.
Complexity of Time: O (n*m^2)
In this way, the framework of our problem is out, the procedure is as follows:
codevs1166 Matrix take-up game interval dp+ high-precision//copyright by ametake#include<cstdio> #include <cstring> #include < algorithm>using namespace Std;const int maxn=80+5;const int maxl=32;int n,m;int a[maxn],f[maxn][maxn],aa[maxn],bb[ Maxn],ans[maxn];int Main () { int ans=0; scanf ("%d%d", &n,&m);//n row m column for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) scanf ("%d", &A[J]); for (int j=1;j<=m;j++) f[j][j]=a[j]; for (int j=1;j<=m-1;j++)//Interval length {for (int k=1;k<=m-j;k++)//start { int l=k+j; F[K][L] = max (A[k] + 2 * f[k+1][l], a[l] + 2 * f[k][l-1]); } } ANS+=2*F[1][M]; } printf ("%d\n", ans);
But wait, why is CE?
We assume an extreme case where the matrix is 80*80, and each item is 1000, the result is the largest, which is 193428131138340667952988000000.
Don't count, this number is 30 bits.
Now, obviously, we're going to use high precision. We don't have Java magic big integers, but we don't have to be as cool as Pascal, we have C + + overloaded operators (Pas also have but do you dare to use = = restricted by the dead accidentally error and no use)
The first time I wrote such a large-scale high-precision reload, I spent the whole morning.
Without any experience, I found the code for CSDN icenternal. Here's a quote.
#include <cstdio> #include <cstring> #include <algorithm>using namespace std; Code is not original, source CSDN user icenternal Source address http://blog.csdn.net/devillaw_zhc/article/details/7776578const int power = 1; //The number of bits for each operation is 10, which is defined here in order to facilitate program implementation of const int base = 10; &NBSP;//10 Power sub-party. To press the bit, just change power and base, such as pressure million-bit high-precision, then power = 4, base = 10000const int MAXL = 1001; //The length of the array. Char A[maxl], b[maxl];struct num{ int a[maxl]; num () {memset (A, 0, sizeof (a));} //initialization num (char *s) , &NB sp;//Initializes a string to a high-precision number { memset (A, 0, sizeof (a)); int len = strlen (s); a[0] = (len+power-1)/power; &NBSp //number of lengths for (int i=0, t=0, W; i < Len; W *= ++i) { if (i% Power = = 0) {w = 1, ++t;} A[T] + = w * (s[i]-' 0 '); } Initialize the array, here's your own simulation, it should be easy to understand ~ } void Add (int k) {if (k | | a[0]) a[++a[0]] = k;} // Add a number at the end of the division, use void Re () {reverse (a+1, a+a[0]+1),} &NBS P //number of digits in turn, use the time division to void print () &N Bsp //print this high precision { & nbsp printf ("%d", a[A[0]]); //print highest bit first, in order to press the position or the high precision number is 0 consider   for (int i = a[0]-1;i > 0;--i) printf ("%0*d", Power, a[i]); //Here "%0*d", power means that the power bit must be output, not enough to be preceded by 0 to top up printf ("\ n"); nbsp }} P,q,ans;bool operator < (const num &P, const num &q) Judgment less than relationship, when division is useful { if (P.a[0] < q.a[0]) return true; if (p.a[0] > q.a[0]) return False;&nbs P for (int i = p.a[0];i > 0;--i) { if (p.a[i]! = Q.a[i]) return P.a[i] < ; q.a[i]; } return false;} num operator + (const num &P, const num &q) //Add, needless to say, simulate again, it's easy to understand { num c; c.a[0] = max (p.a[0], q.a[0]); for (int i = 1;i <= c.a[0];++i) &NB Sp { C.a[i] + + p.a[i] + q.a[i]; C.A[I+1] + = c.A[i]/base; C.a[i]%= base; } if (c.a[c.a[0]+1]) ++c.a[0]; & nbsp return c;} NUM operator-(const num &P, const num &q) //subtraction, needless to say, simulate again, it's easy to understand { num C = p; for (int i = 1;i <= c.a[0];++i) { C.a[i] -= q.a[i]; if (C.a[i] < 0) {C.a[i] + = base;--c.a[i+1];} } while (C.a[0] > 0 &&!c.a[c.a[0])--c.a[0]; //My habit is that if the number is 0, then his length is also 0, which makes it easier to compare sizes and add numbers at the end of the judgment. return c;} NUM operator * (const num &P, const num &q) //multiplication, or analog Once again. In fact, high precision is simulated artificial arithmetic! { num c; c.a[0] = p.a[0]+q.a[0]-1; for (int i = 1;i <= p.a[0];++i) for (int j = 1;j <= q.a[0];++j) { &NBsp C.a[i+j-1] + + p.a[i]*q.a[j]; C.A[I+J] + c.a[i+j-1]/base; C . a[i+j-1]%= base; } if (c.a[c.a[0]+1]) ++c.a[0]; return c;} NUM operator/(const num &P, const num &q) //division, here I'll talk a little bit about { num x, y; for (int i = p.a[0];i >= 1;--i) //starting from the highest bit { Y.add (P.a[i]), &NBSP ; //Add the number to the end (lowest bit), this time is high in front, low in the rear y.re (); //The number in turn, into a unified storage method: Low in front, high in the back &NBSP ; while (!) ( Y < Q)) //greater than or equal to the divisor, if less, the answer is the initial "0" -y = y -Q, ++x.a[i]; //can reduce a few divisor, minus a few times, the answer on the position on the addition of several times. Y.RE (); //The number in turn, preparing for the next add-on } X.a[0] = p.a[0]; while (X.a[0] > 0 &&!x.a[x.a[0]])--x.a[0]; return x;} int main () { scanf ("%s", a); scanf ("%s", b); reverse (A, A+strlen (a)); R Everse (b, B+strlen (b)); p = num (a), q = num (b); ans = p + q; ans.print (); &NB Sp Ans = p-q; ans.print (); ans = p * q; Ans.print (); ans = p/q; Ans.print ();}
The above-mentioned predecessor's code is very concise (compared to the WFWBZ, it is true), benefited, but his heavy load is written outside the structure.
I copied this code in the struct (not in the code above):
num operator = (int b)//Assign a constant to the high-precision structure { num c; c.a[0]=0; while (b) { c.a[0]++; C.a[c.a[0]]=b%base; b/=base; } return c; }
And
num operator + (int b)//stripping structure plus constant { num c; C.A[0]=A[0]; c.a[1]+=b; int i=1; while (C.a[i]>=base) { c.a[i+1]+=c.a[i]/base; C.a[i]%=base; i++; } if (c.a[c.a[0]+1]) ++c.a[0]; return c; }
What makes me baffled, however, is that the two code runs out of effect, specifically:
Main function Output:
int main () { scanf ("%s", a); scanf ("%s", b); Reverse (A, A+strlen (a)); Reverse (b, B+strlen (b)); p = num (a), q = num (b); Ans = p + q; Ans.print (); ans=12345; Ans.print (); ans = ans +; Ans.print (); while (1);
Result Input 111 222
First output 333 correct (other big data also correct)
Second output 333 change to return *this output 12345
Third time output 50
If you're entering big data like 10,000 or so, the third output is 00050.
So I turned out the former WFWBZ god Ben wrote the high-precision template, referring to the previous assignment constant changed to the following, although do not understand why, the result is successful
num operator = (int b) { a[0]=0; while (b) { a[0]++; A[a[0]]=b%base; b/=base; } return *this; }
There is no way to adjust, Leo God Ben said he could not help. At this time I deeply appreciate the importance of friends and predecessors. The solution to this problem, especially to thank Guangrao YQL classmate and last year first-class God Ben, Tsinghua Hym god Ben and will be Tsinghua's Wyw god Ben, patience to explain to me two hours ... Especially Hym predecessors, Junior all kinds of ignorance still don't bother, deeply moved. Originally issued for help thought no one noticed me, the result is a moment everyone to answer, really touched =
Broken up to this end, in short, listen to the predecessors of the explanation summed up the following points:
1. Assignment number and plus sign action principle is different, separate discussion, cannot generalize.
2. For the assignment number, the first mistake in the above procedure cannot redefine a num C, because the variable is a local variable that automatically destroys the memory when the entire function (overloading is equivalent to running a function) finishes. So does return c not work? does not work. The assignment number has its own return value. If we write here (ans=123). Print (), the output is 123, because the output here is the return value, the assignment number returns C,C=123, and the output is 123. But this c of return is not assigned to the left side of the equals sign, but returns only one value but no effect.
So what do we do? In operator, there is a name on the left side of the assignment that takes effect only on the inner wall of the function, which is this.
This is a pointer to the element to the left of the assignment number. Here, it points to the copied num struct.
In other words, the *this operation is done on the left side of the equals sign. For example, we want to make ans.a[0]=b, we can write (*this). A[0]=b, or this->a[0]=b; more recommend the latter.
Finally, we return *this, which is the return value of the assignment number. Although it is not quite understood what the value of the assignment number is, it ensures that both the assignment and the output are correct.
After the change is the second way above
3. For the plus, struct plus structure, you can open a temporary structure C, because the last function is the assignment number, this C will be assigned to the left ans. However, it is not possible to write struct constants.
Why is it? Hym god Ben said so.
These two are really not the same, you remember it first. The university will learn.
What the hell is this? = =
Anyway, it's probably something I can't afford. Orz the world of God Ben
After all, the change should look like this:
num operator + (const int &b) { this->a[1]+=b; int i=1; while (This->a[i]>=base) { this->a[i+1]+=this->a[i]/base; this->a[i]%=base; i++; } if (this->a[this->a[0]+1]) this->a[0]; return *this; }
Since the member function is defined inside the struct, you can use a[1] instead of this->a[1], and after simplification, it should be:
num operator + (const int &b)//this-> can be omitted { a[1]+=b; int i=1; while (A[i]>=base) { a[i+1]+=a[i]/base; A[i]%=base; i++; } if (a[a[0]+1]) a[0]++; return *this; }
And, in fact, it doesn't need to &b direct const to transmit numbers (Guangrao ben).
Here also to add a small problem, by wyw god Ben Friendship Answer:
Finally, why add a const?
A: You need to use the STL to add a const. This is only to be compatible with some STL, and the Const declaration guarantees that the function will not change the value of struct members, otherwise the STL will error.
At the end of the day, I tuned the code for an afternoon just because of a low-level error:
C.a[i]+=a[i]+b.a[i];
It should be + = but I wrote it for the first time = when the rounding is straight =
It turns out, dikes, Yixue. Details determine success or failure tut
OK, finished, release the code June:
--Xisaishan before the egret fly, peach blossom water Mandarin fish Fertilizer
Copyright NOTICE: Reprint Please specify source [ametake Copyright]http://blog.csdn.net/ametake Welcome to see
"Daily Learning" "Interval dp+ high-precision" codevs1166 matrix number Game