WEEK3-2020/10/8
Problem A - Working routine CodeForces-706E
Difficulty: 4 | Tag: Cross LinkList (十字链表)
Vasiliy finally got to work, where there is a huge amount of tasks waiting for him. Vasiliy is given a matrix consisting of n rows and m columns and q tasks. Each task is to swap two submatrices of the given matrix.
For each task Vasiliy knows six integers ai, bi, ci, di, hi, wi, where ai is the index of the row where the top-left corner of the first rectangle is located, bi is the index of its column, ci is the index of the row of the top-left corner of the second rectangle, di is the index of its column, hi is the height of the rectangle and wi is its width.
It’s guaranteed that two rectangles in one query do not overlap and do not touch, that is, no cell belongs to both rectangles, and no two cells belonging to different rectangles share a side. However, rectangles are allowed to share an angle.
Vasiliy wants to know how the matrix will look like after all tasks are performed.
- Input
The first line of the input contains three integers n, m and q (2 ≤ n, m ≤ 1000, 1 ≤ q ≤ 10 000) — the number of rows and columns in matrix, and the number of tasks Vasiliy has to perform.
Then follow n lines containing m integers vi, j (1 ≤ vi, j ≤ 109) each — initial values of the cells of the matrix.
Each of the following q lines contains six integers ai, bi, ci, di, hi, wi (1 ≤ ai, ci, hi ≤ n, 1 ≤ bi, di, wi ≤ m).
- Output
Print n lines containing m integers each — the resulting matrix.
- Sample Input
4 4 2
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
1 1 3 3 2 2
3 1 1 3 2 2
- Sample Output
4 4 3 3
4 4 3 3
2 2 1 1
2 2 1 1
Analysis
If we swap respectively , would lead to TLE. Given that the inner order remains unchanged in terms of one matrix, we just need to swap the borders. We use the cross linklist to implement it.
MyCode
#include <iostream>
#include <algorithm>
using namespace std;
const int Max = 1005;
typedef long long ll;
int n, m, q, h, w;
struct Node
{
ll val;
int r,d;
}A[Max * Max];
int getId(int x,int y)
{
return x*m + y;
}
void Input(Node A[])
{
for(int i=1; i <= n; ++i)
{
for(int j=1; j <= m; ++j)
{
cin >> A[getId(i, j)].val;
}
}
}
void Link()
{
for(int i = 0; i <= n; ++i)
{
for(int j = 0; j <= m; ++j)
{
A[getId(i,j)].r = getId(i,j+1);
A[getId(i,j)].d = getId(i+1,j);
}
}
}
void getStart(int &s, int x, int y)
{
for(int i = 1; i < x; ++i)
s = A[s].d; //行号往下找
for(int i = 1; i < y; ++i)
s = A[s].r; //列号往右找
}
void changeLink_1(int mtr1, int mtr2)
{
for(int i = 1; i <= h; ++i)
{
//开始位于左上角,向下走,交换第一列向右的连接
mtr1 = A[mtr1].d;
mtr2 = A[mtr2].d;
swap(A[mtr1].r, A[mtr2].r);
}
for(int i = 1; i <= w; ++i)
{
//此时位于左下角,再向右走,交换最后行向下的连接
mtr1 = A[mtr1].r;
mtr2 = A[mtr2].r;
swap(A[mtr1].d, A[mtr2].d);
}
}
void changeLink_2(int mtr1, int mtr2)
{
for(int i = 1; i <= w; ++i)
{
//开始位于左上角,向右走,交换第一行向下的连接
mtr1 = A[mtr1].r;
mtr2 = A[mtr2].r;
swap(A[mtr1].d, A[mtr2].d);
}
for(int i = 1; i <= h; ++i)
{
//此时位于右上角,再向下走,交换最后列向右的连接
mtr1 = A[mtr1].d;
mtr2 = A[mtr2].d;
swap(A[mtr1].r, A[mtr2].r);
}
}
void OutPut()
{
int p = 0, tmp;
for(int i = 1; i <= n; ++i)
{
p = A[p].d; //向下一行
tmp = p;
for(int j = 1; j <= m; ++j)
{
tmp = A[tmp].r; //向右一个
cout << A[tmp].val << " ";
}
cout << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m >> q;
Input(A);
Link();
while(q--)
{
int x1, x2, y1, y2, s1 = 0, s2 = 0;
cin >> x1 >> y1 >> x2 >> y2 >> h >> w;
getStart(s1, x1, y1);
getStart(s2, x2, y2);
changeLink_1(s1, s2);
changeLink_2(s1, s2);
}
OutPut();
return 0;
}
Problem B - Sequence I HDU - 5918
Difficulty : 2 | Tag: KMP
Mr. Frog has two sequences a1,a2,⋯,an and b1,b2,⋯,bm and a number p. He wants to know the number of positions q such that sequence b1,b2,⋯,bm is exactly the sequence aq,aq+p,aq+2p,⋯,aq+(m−1)p where q+(m−1)p≤n and q≥1.
- Input
The first line contains only one integer T≤100, which indicates the number of test cases.
Each test case contains three lines.
The first line contains three space-separated integers 1≤n≤106,1≤m≤106 and 1≤p≤106.
The second line contains n integers a1,a2,⋯,an(1≤ai≤109).
the third line contains m integers b1,b2,⋯,bm(1≤bi≤109).
- Output
For each test case, output one line “Case #x: y”, where x is the case number (starting from 1) and y is the number of valid q’s.
- Sample Input
2
6 3 1
1 2 3 1 2 3
1 2 3
6 3 2
1 3 2 2 3 1
1 2 3
- Sample Output
Case #1: 2
Case #2: 1
Analysis
This Problem may be accepted by using brute force, while using KMP is the best way.
Just need to let i++ become i += p; then count all the possible cases in the main chain.
MyCode
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int Max = 1000005;
int a[Max], b[Max], nex[Max];
int n, m, p;
void getNext(int *b)
{
int i, j = -1;
nex[0] = -1;
i = 0;
while(i < m)
{
while(j != -1 && b[i]!= b[j])
j = nex[j];
nex[++i] = ++j;
}
}
int kmp(int *a, int *b)
{
int ans = 0;
getNext(b);
for(int k = 0; k < p; k++)
{
int i = k, j = 0;
while(i < n)
{
while(j != -1 && a[i] != b[j])
j = nex[j];
i += p;
j++;
if(j >= m)
{
ans++;
j = nex[j];
}
}
}
return ans;
}
int main()
{
int t, flag = 1;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d", &n, &m, &p);
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
for(int i = 0; i < m; i++)
scanf("%d", &b[i]);
printf("Case #%d: %d\n", flag++, kmp(a,b));
}
return 0;
}
Problem C - Cyclic Nacklace HDU - 3746
Difficulty : 2 | Tag: KMP
CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of “HDU CakeMan”, he wants to sell some little things to make money. Of course, this is not an easy task.
As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl’s fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls’ lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet’s cycle is 9 and its cyclic count is 2:
Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden.
CC is satisfied with his ideas and ask you for help.
- Input
The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases.
Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by ‘a’ ~‘z’ characters. The length of the string Len: ( 3 <= Len <= 100000 ).
- Output
For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.
- Sample Input
3
aaa
abca
abcde
- Sample Output
0
2
5
Analysis
We just need to use the KMP next array to find the repetend loop body len and everything becomes simple.
MyCode
#include <iostream>
#include <string.h>
using namespace std;
const int Max = 100005;
char a[Max];
int nex[Max];
void getNext(char *a, int *nex, int n)
{
nex[0] = -1;
int i = 0, j = -1;
while(i < n)
{
if(j == -1 | a[i] == a[j])
{
++i;
++j;
nex[i] = j;
}
else
j = nex[j];
}
}
int main()
{
ios::sync_with_stdio(false);
int t, n, loop, res;
cin >> t;
while(t--)
{
memset(nex, 0, Max);
cin >> a;
n = strlen(a);
getNext(a, nex, n);
loop = n - nex[n];
if(n % loop == 0 && loop != n)
res = 0;
else
res = loop - n % loop;
cout << res << endl;
}
}
Problem D - Restoring the Expression CodeForces-898F
Difficulty : 4 | Tag: String Hash
A correct expression of the form a+b=c was written; a, b and c are non-negative integers without leading zeros. In this expression, the plus and equally signs were lost. The task is to restore the expression. In other words, one character ‘+’ and one character ‘=’ should be inserted into given sequence of digits so that:
- character’+’ is placed on the left of character ‘=’,
- characters ‘+’ and ‘=’ split the sequence into three non-empty subsequences consisting of digits (let’s call the left part a, the middle part — b and the right part — c),
- all the three parts a, b and c do not contain leading zeros,
- it is true that a+b=c.
It is guaranteed that in given tests answer always exists.
- Input
The first line contains a non-empty string consisting of digits. The length of the string does not exceed 10^6.
- Output
Output the restored expression. If there are several solutions, you can print any of them.
Note that the answer at first should contain two terms (divided with symbol ‘+’), and then the result of their addition, before which symbol’=’ should be.
Do not separate numbers and operation signs with spaces. Strictly follow the output format given in the examples.
If you remove symbol ‘+’ and symbol ‘=’ from answer string you should get a string, same as string from the input data.
- Sample Input
12345168
- Sample Output
123+45=168
Analysis
If we just go through all the cases, we will definitely get TLE. So we need to simply identify whether the answer is possibly true. It then comes to string Hash. There are two ways.
One Hash with Check
One way is hash one time and check whether it’s true, combining with the Problem E (a + b Problem), which is a good way to choose.
Two Hash without Collide
If we choose the Prime Num carefully, and Hash two times, may be we can get though it.
MyCode
I use the first method.
#include <iostream>
#include <string.h>
using namespace std;
typedef unsigned long long ull;
const int Max = 1000005;
const int base = 10;
const ull mod = 1e9 + 7;
ull h[Max],p[Max];
char s[Max];
int len;
ull sum;
void hash_()
{
h[0] = 0;
p[0] = 1;
for(int i = 1; i <= len; ++i)
{
h[i] = (h[i - 1] * base + s[i] - '0') % mod;
p[i] = p[i -1] * base % mod;
}
}
ull getSubHash(int l, int r)
{
return ((h[r] - h[l - 1] * p[r - l + 1] % mod) + mod) % mod;
}
bool check_plus(char* x, int xLen, char* y, int yLen, char* sum, int sLen)
{
ull xInt = 0,yInt = 0,sInt = 0;
for(int i = 0; i < xLen; ++i)
{
xInt = xInt * 10 + (x[i] - '0');
}
for(int i = 0; i < yLen; ++i)
{
yInt = yInt * 10 + (y[i] - '0');
}
for(int i = 0; i < sLen; ++i)
{
sInt = sInt * 10 + (sum[i] - '0');
}
return xInt + yInt == sInt;
}
inline bool checkZero(int x, int y)
{
if(y - x != 1 && s[x+1] == '0')
return false;
if(!s[x] && !s[y] && !s[y + 1])
return false;
return true;
}
bool check(int x, int y)
{
if(checkZero(x, y) && (getSubHash(1, x) + getSubHash(x + 1, y)) % mod == sum)
return check_plus(s + 1, x, s + x + 1, y - x, s + y + 1, len - y);
return false;
}
void Print(int x, int y)
{
for(int i = 1; i <= x; ++i)
cout << s[i];
cout << "+";
for(int i = x + 1; i <= y; ++i)
cout << s[i];
cout << "=";
for(int i = y + 1; i <= len; ++i)
cout << s[i];
cout << endl;
}
int main()
{
scanf("%s", s+1);
len = strlen(s + 1);
hash_();
for(int i = len - 1; i > 1 && i >= len - i; --i)
{
int x = len - i, y = i;
sum = getSubHash(i + 1, len);
if(check(x, y))
{
Print(x, y);
return 0;
}
else if(check(x - 1, y))
{
Print(x - 1, y);
return 0;
}
else if(check(y - x + 1, y))
{
Print(y - x + 1, y);
return 0;
}
else if(check(y - x, y))
{
Print(y - x, y);
return 0;
}
}
}
Be careful to return when you find one correct answer, otherwise will come to a WA.
Problem E - A+B Problem II HDU-1002
Difficulty: Naive | Tag: str
I have a very simple problem for you. Given two integers A and B, your job is to calculate the Sum of A + B.
- Input
The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line consists of two positive integers, A and B. Notice that the integers are very large, that means you should not process them by using 32-bit integer. You may assume the length of each integer will not exceed 1000.
- Output
For each test case, you should output two lines. The first line is “Case #:”, # means the number of the test case. The second line is the an equation “A + B = Sum”, Sum means the result of A + B. Note there are some spaces int the equation. Output a blank line between two test cases.
- Sample Input
2
1 2
112233445566778899 998877665544332211
- Sample Output
Case 1:
1 + 2 = 3
Case 2:
112233445566778899 + 998877665544332211 = 1111111111111111110
Analysis
Just use a carry. It’s pretty easy. Be careful to set the a, b back to 0.
MyCode
#include <iostream>
#include <string.h>
using namespace std;
const int Max = 1005;
int a[Max],b[Max];
int main()
{
int n;
string s1,s2;
cin >> n;
for(int i = 0; i < n; ++i)
{
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
int c[Max];
cin >> s1 >> s2;
for(int j = 0; j < s1.length() ; ++j)
a[j] = s1[s1.length() - 1 - j] - 48;
for(int j = 0; j < s2.length() ; ++j)
b[j] = s2[s2.length() - 1 - j] - 48;
int carry = 0;
int upper = max(s1.length(), s2.length());
for(int j = 0; j < upper ; ++j)
{
c[j] = a[j] + b[j] + carry;
carry = c[j] / 10;
c[j] %= 10;
}
c[upper] = carry;
if(carry != 0)
++upper;
cout << "Case " << i + 1 << ":" << endl;
cout << s1 << " + " << s2 << " = ";
for(int j = upper - 1; j >= 0 ; --j)
{
cout << c[j];
}
cout << endl;
if(i != n - 1)
cout << endl;
}
return 0;
}