Question
State compression Dynamic Planning (DP) is a dynamic planning that uses binary numbers to represent states.
We often use 1 in binary to select the State represented by this bit, and 0 to indicate the opposite meaning.
For example, if there is a graph with \ (n \) nodes, we need to find the shortest path through some specific points.
? Assume \ (n = 8 \), the meaning of the binary number 10010011 is as follows:
Node number |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Binary Number |
1 |
0 |
0 |
1 |
0 |
0 |
1 |
1 |
Whether the current node exists |
Y |
N |
N |
Y |
N |
N |
Y |
Y |
In this way, we can use \ (2 ^ n-1 \) binary numbers to represent all States.
However, we know that the number of \ (2 ^ n \) will become very large when \ (n \) is large, this also determines a significant feature of the question-\ (n \) value is small
At the same time, in order to get better time, we often subtract many unnecessary states.
This step is implemented through bitwise operations.
Bitwise operation
After the status is obtained, we will perform some access and operations on these statuses, which requires in-place calculation.
Common bitwise operations include the following sets:
1. '&' symbol, \ (x \ & Y \) indicates the sum operation of X and Y
2. '|', \ (X | Y \) indicates the or operation between x and y.
3. The '^' symbol indicates the XOR operation of X and Y (same as 0, not the same as 1)
4. <and>, <is left shift, for example, \ (x <2 \) it indicates moving each digit in the binary of X to the right by two digits (the new occurrence is supplemented by 0)
? Similarly,> is right shift. \ (x> 1 \) indicates removing the binary value of X.
5 ,~ Symbol, indicating that the binary is reversed (as the name suggests). However, pay special attention to the storage of negative numbers in the binary system, but it does not seem to be used much.
The preceding operations can be used to perform basic but important operations.
1. Determine whether the I-th digit of binary number X is 1
? Method: \ (if (1 <(I-1) \ & X) \), we use \ (1 <(I-1 )\) construct a number that is 1 on the \ (I \) bits, and perform operations with X directly.
2. Change the I of a binary number X to 1.
? Method: \ (x = x | (1 <(I-1) \), roughly the same as 1, but changed & to |
3. Enumeration subset \ (x \ & (x-1 )\)
? At first glance, this step removes 1 in the rightmost position of X, but think about it because it is not a bit of 1 in X, the bit corresponding to the new number cannot be 1, and the bit of 1 in X may not be 1, so we can use this method to enumerate the subsets in the State represented by X.
4. Remove the I-to-1 in binary number x (ensure that there is 1 on the I-bit)
? Method: x ^ (1 <(I-1) is similar to the above
Example 1: poj3311
Hie with the pie
Time limit:2000 ms |
|
Memory limit:65536 K |
Total submissions:10034 |
|
Accepted:5416 |
Description
The pizazz pizzeria prides itself in delivering pizzas to its customers as fast as possible. unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. he will wait for 1 or more (up to 10) orders to be processed before he starts any deliveries. needless to say, he wowould like to take the shortest route in delivering these goodies and returning to the pizzeria, even if it means passing the same location (s) or the pizzeria more than once on the way. he has commissioned you to write a program to help him.
Input
Input will consist of multiple test cases. The first line will contain a single integerNIndicating the number of orders to deliver, where 1 ≤N≤ 10. After this will beN+ 1 lines each containingN+ 1 integers indicating the times to travel between the pizzeria (numbered 0) andNLocations (numbers 1N).JTh value onITh line indicates the time to go directly from locationITo locationJWithout visiting any other locations along the way. Note that there may be quicker ways to go fromIToJVia other locations, due to different speed limits, traffic lights, etc. Also, the time values may not be between RIC, I. e., the time to go directly from locationIToJMay not be the same as the time to go directly from locationJToI. An input valueN= 0 will terminate input.
Output
For each test case, you shoshould output a single number indicating the minimum time to deliver all of the pizzas and return to the pizzeria.
Sample Input
30 1 10 101 0 1 210 1 0 1010 2 10 00
Sample output
8
Source
East central North America 2006
A person needs to deliver n pieces of goods, and a matrix is provided to represent a graph (n <= 10), indicating the time of the direct path between any two points, obtain the minimum delivery time from the starting point 0 (arrive at the specified n locations) and return to the starting point 0.
Question: If n is so small, we have to consider the pressure.
? Because we need to return to the minimum path of the starting point, we can consider splitting the path into two parts-from the starting point to a certain point, and then back to the starting point, the latter part has only one path
? It is obvious that Floyd will first be used to find the shortest path between all points.
? The following is the design status. We use \ (DP [I] [J] \) to indicate the status of \ (I \) (that is, the points that have passed) the shortest time taken when the end point is \ (J. Obviously, we have performed pressure on \ (I \).
? 1) if \ (I \) has only one digit and is \ (J \), add the time from the start point to \ (J \).
? 2) If \ (I \) does not only have \ (J \), we should consider transferring from a certain point in the middle \ (k \) as a relay point.
? Transfer Equation \ (DP [I] [J] = min (DP [I] [J], DP [I \ Text ^ (1 <(J-1)] [k] + dis [J] [k]) \)
? Finally, follow the above statistical answer.
#include<iostream>#include<string.h>#include<string>#include<stdio.h>#include<algorithm>#include<vector>#include<queue>#include<map>using namespace std;int dp[10100][12],n,sq[12][12]; int read(){ int x=0,f=1;char ch=getchar(); while ((ch<‘0‘) || (ch>‘9‘)) {if (ch==‘-‘) f=-1;ch=getchar();} while ((ch>=‘0‘) && (ch<=‘9‘)) {x=x*10+(ch-‘0‘);ch=getchar();} return x*f;}int main(){ while ((scanf("%d",&n)!=EOF) && (n)) { int i,j,k; for (i=0;i<=n;i++) for (j=0;j<=n;j++) sq[i][j]=read(); for (k=0;k<=n;k++) { for (i=0;i<=n;i++) { for (j=0;j<=n;j++) sq[i][j]=min(sq[i][j],sq[i][k]+sq[k][j]); } } for (i=0;i<(1<<n);i++) { for (j=1;j<=n;j++) { if (i==(1<<(j-1))) dp[i][j]=sq[0][j]; else { dp[i][j]=1e9+7; for (k=1;k<=n;k++) if ((j!=k) && (i&(1<<(j-1)))) dp[i][j]=min(dp[i][j],dp[i^(1<<(j-1))][k]+sq[k][j]); } } } int ans=1e9+7,all=(1<<n)-1; for (i=1;i<=n;i++) ans=min(ans,dp[all][i]+sq[i][0]); printf("%d\n",ans); } return 0;}/*30 1 10 101 0 1 210 1 0 1010 2 10 00*/
2. [usaco 08nov] mixed up cows
Description
Each of Farmer John's n (4 <= n <= 16) cows has a unique serial number s_ I (1 <= s_ I <= 25,000 ). the cows are so proud of it that each one now wears her number in a gangsta manner engraved in large letters on a gold plate hung around her ample bovine neck.
Gangsta cows are rebellious and line up to be milked in an order called 'mixed up '. A cow order is 'mixed' if the sequence of serial numbers formed by their milking line is such that the serial numbers of every pair of consecutive cows in line differs by more than K (1 <= k <= 3400 ). for example, if n = 6 and K = 1 then 1, 3, 5, 2, 6, 4 is a 'mixed' up 'lineup but 1, 3, 6, 5, 2, 4 is not (since the consecutive numbers 5 and 6 differ by 1 ).
How many different ways can n cows be mixed up?
For your first 10 submissions, You will be provided with the results of running your program on a part of the actual test data.
John's family has native cows. The number of the I-th cow is si, and the number of each cow is unique. These cows have been in bad temper recently. To express their dissatisfaction, they must be in disorder when milking. In a chaotic team, the numbers of neighboring cows are more than K. For example, when k = 1, 1, 3, 5, 2, 6, 4 is a chaotic team, and 1, 3, 6, 5, 2, 4 is not, because 6 and 5 are only 1 different. Please count. How many formations are chaotic?
Input/Output Format
Input Format:
* Line 1: two space-separated integers: N and K
* Lines 2. n + 1: line I + 1 contains a single integer that is the serial number of cow I: s_ I
Output Format:
* Line 1: A single integer that is the number of ways that N cows can be 'mixed'. The answer is guaranteed to fit in a 64-bit integer.
Input and Output sample
Input example #1:
4 1 3 4 2 1
Output sample #1:
2
Description
The 2 possible mixed up arrangements are:
3 1 4 2
2 4 1 3
This question is better than the above question.
As soon as we see \ (4 \ Leq n \ Leq 16 \), we know we want to compress it.
\ (DP [I] [J] \) indicates that the current status is \ (I \), and the last one that is added to this status is \ (J \)
The transfer equation is obvious. If \ (J \) is in the \ (I \) State and \ (k \) is not, then \ (DP [(1> (k-1) | I] [k] + = DP [I] [J] \)
The final answer is \ (\ sum ^ N _ {I = 1} {DP [(1 <n)-1] [I]} \).
#include<iostream>#include<string.h>#include<string>#include<stdio.h>#include<algorithm>#include<math.h>#include<vector>#include<queue>#include<map>using namespace std;long long dp[100100][18];int n,high[18],cha;int read(){ int x=0,f=1;char ch=getchar(); while ((ch<‘0‘) || (ch>‘9‘)) {if (ch==‘-‘) f=-1;ch=getchar();} while ((ch>=‘0‘) && (ch<=‘9‘)) {x=x*10+(ch-‘0‘);ch=getchar();} return x*f;}int main(){ memset(dp,0,sizeof(dp)); n=read();cha=read(); int i,j,k; for (i=1;i<=n;i++) {high[i]=read();dp[1<<(i-1)][i]=1;} int all=(1<<n)-1; //cout << all << endl; for (i=1;i<=all;i++) { for (j=1;j<=n;j++) { for (k=1;k<=n;k++) { if ((abs(high[j]-high[k])<=cha) && ((1<<(j-1))&i) && (((1<<(k-1))&i)==0)) dp[(1<<(k-1))|i][k]+=dp[i][j]; } } } long long ans=0; for (i=1;i<=n;i++) ans+=dp[all][i]; printf("%lld",ans); return 0;}/*4 1 3 4 2 1 */
3. [usaco 06nov] corn fields
Description
Farmer John has purchased a lush New Rectangular pasture composed of m by N (1 ≤ m ≤ 12; 1 ≤ n ≤ 12) Square parcels. he wants to grow some yummy corn for the cows on a number of squares. regrettably, some of the squares are infertile and can't be planted. the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. he has not yet made the final choice as to which squares to plant.
Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. he is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.
John bought a new rectangular farm which is divided into n columns (1 ≤ m ≤ 12; 1 ≤ n ≤ 12 ), each grid is a square area. John is planning to plant delicious grass in a few gr on the farm for his cows to enjoy.
Unfortunately, some land is quite poor and cannot be used for planting grass. In addition, the cows like the idea of monopolizing a lawn, so John won't choose two adjacent lands, that is, no two lawns have a public edge.
John wants to know, if he does not consider the total number of lawns, how many planting schemes are available to him? (Of course, it is also a solution to completely abandon the new farm)
Input/Output Format
Input Format:
The first line: two integers m and n, separated by spaces.
Lines 2nd to m + 1: Each line contains N integers separated by spaces, describing the status of each land. Line I + 1 describes the land in line I. All integers are 0 or 1. If it is 1, it indicates that the land is fertile enough. If it is 0, it indicates that the land is not suitable for planting grass.
Output Format:
An integer, that is, the total number of farm distribution solutions divided by the remainder of 100,000,000.
Input and Output sample
Input example #1:
2 31 1 10 1 0
Output sample #1:
9
We obviously found that each row is relatively independent. That is, the status of this line (whether it is legal) does not affect whether the next line is legal
With this idea, we can consider whether the field of each row can be squashed, and at the same time pre-process all legal situations.
So an important question is: how to determine the current State (as \ (now \) as a valid state)
We know that a status is valid only when there is no adjacent 1 in this status.
That is, shift \ (now \) to the left or right, with the & 0 of the original value
Writing: \ (now \ Text & (now> 1) \ Text & (now <1 )))\)
Then it will be simpler.
Note \ (DP [I] [J] \) is taken to the \ (I \) Row, and the current selected status of this row is \ (J \) number of solutions
Ensure that \ (J \) is valid (it is legal and can exist in this line)
We enumerate the status \ (k \) of the previous row. When the statuses of these two rows are valid (\ (J \ Text & K = 0 \)) we perform the transfer (\ (DP [I] [J] + = DP [I-1] [k] \)
The final answer is \ (\ sum ^ {All }_{ I = 0} DP [m] [I] \)
#include<iostream>#include<string.h>#include<string>#include<stdio.h>#include<algorithm>#include<vector>#include<queue>#include<map>using namespace std;const int maxd=1e9;int sq[13][13],n,m,dp[13][10100],maxs,hang[13];bool sit[10100];int read(){ int x=0,f=1;char ch=getchar(); while ((ch<‘0‘) || (ch>‘9‘)) {if (ch==‘-‘) f=-1;ch=getchar();} while ((ch>=‘0‘) && (ch<=‘9‘)) {x=x*10+(ch-‘0‘);ch=getchar();} return x*f;}int main(){ m=read();n=read(); int i,j,k; for (i=1;i<=m;i++) { for (j=1;j<=n;j++) sq[i][j]=read(); } memset(hang,0,sizeof(hang)); maxs=1<<n; for (i=1;i<=m;i++) for (j=1;j<=n;j++) hang[i]=(hang[i]<<1)+sq[i][j]; for (i=0;i<maxs;i++) sit[i]=(((i&(i>>1))==0) && ((i&(i<<1))==0)); //for (i=0;i<maxs;i++) cout << sit[i] << " ";cout << endl; memset(dp,0,sizeof(dp));dp[0][0]=1; for (i=1;i<=m;i++) { for (j=0;j<maxs;j++) { if ((sit[j]) && ((hang[i]&j)==j)) { for (k=0;k<maxs;k++) if (!(k&j)) dp[i][j]=(dp[i][j]+dp[i-1][k])%maxd; } } } int ans=0; for (i=0;i<maxs;i++) ans=(ans+dp[m][i])%maxd; printf("%d",ans); return 0;}
4. Square Subsets
C. Square Subsets
Time limit per test
4 seconds
Memory limit per test
256 megabytes
Input
Standard Input
Output
Standard output
Petya was late for the lesson too. The teacher gave him an additional task. For some ArrayAPetya shoshould find the number of different ways to select non-empty subset of elements from it in such a way that their product is equal to a square of Some integer.
Two ways are considered different if sets of indexes of elements chosen by these ways are different.
Since the answer can be very large, you shocould find the answer modulo 109? +? 7.
Input
First line contains one integerN(1? ≤?N? ≤? 105)-the number of elements in the array.
Second line containsNIntegers * A ** I * (1? ≤? * A ** I *? ≤? 70)-the elements of the array.
Output
Print one integer-the number of different ways to choose some elements so that their product is a square of a certain integer modulo 109? +? 7.
Examples
Input
Copy
41 1 1 1
Output
Copy
15
Input
Copy
42 2 2 2
Output
Copy
7
Input
51 2 4 5 8
Output
7
Note
In first sample product of elements chosen by any way is 1 and 1? =? 12. So the answer is 24? -? 1? =? 15.
In second sample there are six different ways to choose elements so that their product is 4, and only one way so that their product is 16. So the answer is 6? +? 1? =? 7.
How can a zzr Blog have no question about CF?
The breakthrough in this question is \ (1 \ Leq a_ I \ Leq 70 \), which is obviously subject to pressure.
However, your problem-solving strategy directly determines the time complexity and space complexity.
Normal Pressure is definitely not acceptable. We need to consider some interesting properties.
If a number is a complete number, the power of each prime factor in its prime factor decomposition is an even number.
However, we have noticed that there are only 19 quality factors not greater than 70.
By combining the two, we can record the status \ (I \) as a binary representation of the \ (I \) '\ (J \) bit to represent the \ (J \) parity of prime numbers in a certain number of prime factor decomposition
At the same time, "\ (DP [I] [J] \)" indicates the number of currently selected items \ (I \). The product prime factor decomposition can be expressed as the number of solutions \ (J \).
For each number \ (x \) in a sequence, remember \ (SIT [x] \) as its prime factor decomposition.
We first drop all \ (x \) into a bucket and remember the number of occurrences of \ (CNT [I] \) in the sequence.
It is easy to write the DP sub-statement:
\ (DP [I] [J] = \ sum ^ {all} _ {J = 0} DP [I-1] [J] * 2 ^ {cnt_i-1 }\)
\ (DP [I] [J \ Text ^ sit [I] = \ sum ^ {All }_{ J = 0} DP [I-1] [J] * 2 ^ {cnt_i-1 }\)
For an existing product, we multiply it by \ (I ^ K (k \ in Z) \). If \ (k \) is an even number, then it will not have a new impact on the original prime factor decomposition,
Otherwise, if \ (k \) is an odd number, the odd number of quality factors that it has the same as the current status will become an even number, the odd-number prime factor that it has will bring a new odd-number prime factor to the new state, so we can perform an exclusive or operation.
If the number \ (I \) does not appear, \ (DP [I] [J] \) inherits from \ (DP [I-1] [J] \) directly, the final answer is \ (DP [70] [0]-1 \) (all qualitative factors are even numbers, but you need to remove all numbers from selection)
The time complexity is about \ (O (70*2 ^ {19 })\)
Then there is a space problem.
Size of the \ (DP \) array we opened: \ (70*2 ^ {19} * 4 \ approx 1.4*10 ^ 8B = 140mb \), just past the card
However, long cannot be enabled. Otherwise, the space is \ (280mb \) and MLE is used directly.
The solution is either to open \ (long \) before the variable name, or to use a scrolling array.
The following procedure uses the first method
#include<iostream>#include<string.h>#include<string>#include<stdio.h>#include<algorithm>#include<vector>#include<queue>#include<map>using namespace std;const int maxd=1e9+7,pri[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};int n,cnt[71],sit[71],dp[71][1<<19],powe[100500];int read(){ int x=0,f=1;char ch=getchar(); while ((ch<‘0‘) || (ch>‘9‘)) {if (ch==‘-‘) f=-1;ch=getchar();} while ((ch>=‘0‘) && (ch<=‘9‘)) {x=x*10+(ch-‘0‘);ch=getchar();} return x*f;}void init(){ int i,j; memset(sit,0,sizeof(sit)); for (i=2;i<=70;i++) { int x=i; for (j=0;j<19;j++) { while (x%pri[j]==0) {x/=pri[j];sit[i]^=(1<<j);} } }}int main(){ n=read();init(); int i,j,all=(1<<19); memset(cnt,0,sizeof(cnt)); for (i=1;i<=n;i++) {int x=read();cnt[x]++;} powe[0]=1; for (i=1;i<=n;i++) powe[i]=(powe[i-1]*2)%maxd; memset(dp,0,sizeof(dp));dp[0][0]=1; for (i=1;i<=70;i++) { if (cnt[i]) { //cout << i << " " << cnt[i] << endl; for (j=0;j<all;j++) { dp[i][j]=((long long)dp[i][j]+(long long)dp[i-1][j]*powe[cnt[i]-1])%maxd; dp[i][j^sit[i]]=((long long)dp[i][j^sit[i]]+(long long)dp[i-1][j]*powe[cnt[i]-1])%maxd; } } else { for (j=0;j<all;j++) dp[i][j]=dp[i-1][j]; } } printf("%d",(dp[70][0]-1+maxd)%maxd); return 0;}
Pressure DP entry