0%

Intuition

If we try to use brute-force algorithm to solve this problem, we will find O(2^n) in complexity. But, since max of n is 40, it’s too long to pass. Namely, $2^{40}\sim 10^{12}$. Also, although it looks like a dynamic programming problem, it’s not working either.

Surprisingly, it’s easier than I thought. All we have to do is divide it into half. That way, the complexity will became $2^{n/2}+2^{n/2}$, which has a maximum of $2^{20}+2^{20}=2^{21}\sim 2*10^{6}$.

But, that only include time of 2 brute-force divide. We have to also conquer it. There’s the procedure,

  1. devide all numbers into nums1, nums2 equaly
  2. nums1 -> map1 (possible sum, combinations), also, nums2 -> map2.
  3. for each map1 value, find a value in map2 that satisfy val1 + val2 = target.

combinations

how many combinations in nums1 can construct that sum

Therefore, we get the total complexity is $Time=2*2^{n}*lg(2^n)+2^{n}*lg(2^n)={3}*2^{n}*n$ , where n has a maximum of 20. Namely, we obtain the worse case run time is
$$O_w({3}*2^{n}*n)={3}*2^{20}*20\sim {6}*10^7$$

Sample Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <bits/stdc++.h>
using namespace std;

#define ll long long

ll n, target, res;

void build_mp(vector<ll> &nums, unordered_map<ll, ll> &mp)
{
ll m = 1 << nums.size();
for (ll i = 0; i < m; i++)
{
ll sum = 0;
for (ll j = 0; j < nums.size(); j++)
if ((1 << j) & i)
sum += nums[j];
mp[sum]++;
}
}

int main()
{
while (cin >> n >> target)
{
ll bpt = n / 2;
res = 0;
vector<ll> nums1(bpt), nums2(n - bpt);
for (int i = 0; i < nums1.size(); i++)
cin >> nums1[i];
for (int i = 0; i < nums2.size(); i++)
cin >> nums2[i];
unordered_map<ll, ll> mp1, mp2;
build_mp(nums1, mp1);
build_mp(nums2, mp2);
for (auto it : mp1)
{
ll goal = target - it.first;
if (mp2.find(goal) != mp2.end())
res += it.second * mp2[goal];
}
// when target == 0, (none) set cannot exist, while (0,0) is okay.
if (target == 0)
res--;
cout << res << "\n";
}
}

Intuition

Since the total informant can only be up to 20, we can use an integer to represent if it’s reliable by :

1
2
3
4
5
reliable table
00001 : A is reliable
00010 : B is reliable
00110 : B and C is reliable
...etc.

So as the unreliables.

Brute force : pull out every possibilities

Since we discover that n informant has to represent with n bits, the full range of the possibles is $0$ ~ $2^n-1$ with it represented in int.

And per possibilities, we have to verify it with every informant that is reliable to tell if it’s a valid possible reliable informants allocation.

Therefore, we can calculate a time complexity of:
$$O(2^N*N)$$
Where $N$ is the number of informants. Since $N$ has maximum value of 20, it cost at most $2^{20}*20 \sim {2}*10^7$, which will not TLE at most judge.

Sample Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <bits/stdc++.h>
using namespace std;

int main()
{
int nums[21], fnums[21];
int n, m;
while (cin >> n >> m && n)
{
// reset
memset(nums, 0, sizeof(nums));
memset(fnums, 0, sizeof(fnums));
// handle input
int x, y;
for (int i = 0; i < m; i++)
{
cin >> x >> y;
if (y > 0)
nums[x - 1] |= 1 << y - 1;
else
fnums[x - 1] |= 1 << -y - 1;
}
// solve
int hightest = (1 << n), res = 0;
for (int i = 0; i < hightest; i++)
{
int now = __builtin_popcount(i), ni = (~i);
if (res >= now)
continue;
bool flag = true;
for (int j = 0; j < n; j++)
if ((i & (1 << j)) && ((fnums[j] & ni) != fnums[j] || (nums[j] & i) != nums[j]))
{
flag = false;
break;
}
if (flag)
res = now;
}
cout << res << endl;
}
}

Observation

This problem gives us two numbers, num1, num2.
Suppose num1 < num2, although might be arbitrary.
Therefore, it’s actually calculate 0 ~ num2 - 0 ~ num1 in every number.

The Problem : Calculate 1 ~ num

To calculate various numbers in 1 ~ num, I use 3 steps. Let b be the maximum that satisfy num / pow(10,b) > 0.

  1. calculate 1 ~ pow(10,b)-1, or 1 ~ 999...99, we can recursively solve this by use count_numbers(pow(10,b)-1).
  2. calculate the midst of the number, or 10...00 ~ X0...00 - 1, where X is the leading number of num.
  3. calculate the back, or X0...00 ~ num

Sample Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define INF 99999999
#define MAXN 1e8
int base[9] = {0, 1, 20, 300, 4000, 50000, 600000, 7000000, 80000000};

void solve(vector<int> &res, int num)
{
if (num == 0)
return;
vector<int> v;
for (int temp = num; temp; temp /= 10)
v.push_back(temp % 10);
reverse(v.begin(), v.end());
int b = v.size() - 1;
// front : (0 ~ 999...99]
solve(res, pow(10, b) - 1);

// middle : 100...0 ~ x00...0 - 1
for (int j = 0; j < res.size(); j++)
res[j] += (v[0] - 1) * base[b];
for (int j = v[0] - 1; j > 0; j--)
res[j] += pow(10, b);
// back : num % pow(10,b)
// int bNum = num % (int)pow(10,b);
res[v[0]] += (num % (int)pow(10, b)) + 1;
for (int i = 1; i < v.size(); i++)
{
b--;
for (int j = 0; j < res.size(); j++)
res[j] += v[i] * base[b];

for (int j = 0; j < v[i]; j++)
res[j] += pow(10, b);
res[v[i]] += (num % (int)pow(10, b)) + 1;
}
}

int main()
{
int num1, num2;
while (cin >> num1 >> num2 && num1 && num2)
{
if (num1 > num2)
swap(num1, num2);
vector<int> res1(10, 0);
vector<int> res2(10, 0);
solve(res1, num1 - 1);
solve(res2, num2);
for (int i = 0; i < res1.size(); i++)
{
cout << res2[i] - res1[i];
if (i != res1.size() - 1)
cout << " ";
}
cout << "\n";
}
}

Intuition

We are told to micmic the polynomial multiplication. Such as, $(x-1)(x-1)=x^2-2x+1$, etc.
So, if you do it correctly, it would be correct.

p.s. You should use long long in this question.

Sample Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <bits/stdc++.h>
using namespace std;

#define ll long long

void addPoly(vector<ll> &poly1, vector<ll> &poly2, ll val = 1, int shift = 0)
{
vector<ll> res(max(poly1.size(), poly2.size() + shift), 0);
for (ll i = 0; i < poly1.size(); i++)
res[i] = poly1[i];
for (ll i = 0; i < poly2.size(); i++)
res[i + shift] += poly2[i] * val;
poly1 = res;
}

void multiply(vector<ll> &poly1, vector<ll> &poly2)
{
vector<ll> res(poly1.size() + poly2.size(), 0);
for (ll i = 0; i < poly2.size(); i++)
addPoly(res, poly1, poly2[i], i);
poly1 = res;
while (poly1.back() == 0)
poly1.pop_back();
}

int main()
{
int n;
while (cin >> n)
{
vector<ll> res(1, 1);
for (ll i = 0; i < n; i++)
{
vector<ll> temp(2, 1);
cin >> temp[0];
temp[0] = -temp[0];
multiply(res, temp);
}

for (ll i = res.size() - 1; i >= 0; i--)
{
if (!i)
{
if (i == res.size() - 1)
;
else if (res[i] >= 0)
cout << " + ";
else
{
cout << " - ";
res[i] = -res[i];
}
cout << res[i];
continue;
}
if (!res[i] || i == res.size() - 1)
;
else if (res[i] < 0)
{
cout << " - ";
res[i] = -res[i];
}
else if (res[i] > 0)
cout << " + ";

if (res[i] > 1)
cout << res[i];
if (res[i])
{
cout << "x";
if (i > 1)
cout << "^" << i;
}
}
cout << " = 0\n";
}
}

Observation

From row8 to row1, We can find an interesting fact : if we assign id 1 ~ 8 to row 8 ~ row 1, respectfully. Let’s say the red balloon in id i is bal[i]. We can get a interesting formula bal[i] = bal[i/2]*2.

Also, $\sum^{2^n}bal[i]$ can be respresent as $3^{n-1}$.

Intuition

We can also see $\sum^{M}bal[i]$ in a very different way that can provide time complexity to O(log(n)): Use $\sum^{2^n}bal[i] = 3^{n-1}$

That is, compute $\sum^{M}bal[i] = \sum^{2^{x_1}}bal[i] + \sum^{2^{x_2}}bal[i] + … + \sum^{2^{x_k}}bal[i]$, where $M=2^{x_1}+2^{x_2}+…+2^{x_k}$.

Sample Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define INF 99999999

int main()
{
vector<ll> dp(31, 1);
for (int i = 1; i <= 30; i++)
dp[i] = dp[i - 1] * 3;
int n, tt = 0;
cin >> n;
while (n--)
{
ll k, a, b;
cin >> k >> a >> b;
a = (ll)(1 << k) - a + 1;
b = (ll)(1 << k) - b;
ll a1 = 0, b1 = 0, t = 1;
for (int i = 30; i >= 0; i--)
{
if ((a >> i) & 1)
{
a1 += dp[i] * t;
t = t << 1;
}
}
t = 1;
for (int i = 30; i >= 0; i--)
{
if ((b >> i) & 1)
{
b1 += dp[i] * t;
t = t << 1;
}
}
cout << "Case " << ++tt << ": " << (a1 - b1) << endl;
}
}

Intuition

Contruct a tower of Babylon use Blocks.
Since Blocks can be flip, we got 6 different cases with one type of block.
Put them into a vector, sort them, and it’s a simple LIS problem.

p.s. One difference from typical LIS problem is that it’s wants maximum height.

Example Code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>
using namespace std;

#define mpb(x, y, z) v.push_back({x, y, z})

int main()
{
int tt = 0;
int n;
while (cin >> n && n)
{
vector<vector<int>> v;
for (int i = 0; i < n; i++)
{
int x, y, z;
cin >> x >> y >> z;
mpb(x, y, z);
mpb(x, z, y);
mpb(y, x, z);
mpb(y, z, x);
mpb(z, x, y);
mpb(z, y, x);
}
sort(v.begin(), v.end());
vector<int> dp(v.size() + 1, 0);
for (int i = 0; i < v.size(); i++)
{
dp[i] = v[i][2];
for (int j = 0; j < i; j++)
{
if (v[i][0] > v[j][0] && v[i][1] > v[j][1])
dp[i] = max(dp[i], dp[j] + v[i][2]);
}
}
int res = *max_element(dp.begin(), dp.end());
cout << "Case " << ++tt << ": maximum height = " << res << "\n";
}
}

UVA-10931 Parity

A simply bit-wise operation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <bits/stdc++.h>
using namespace std;
#define ll long long

int main()
{
ll x;
while (cin >> x && x)
{
ll res = 0;
cout << "The parity of ";
bool y = false;
for (int i = 32; i >= 0; i--)
if ((x >> i) & 1)
{
res++;
cout << 1;
y = true;
}
else if (y)
cout << 0;
cout << " is " << res << " (mod 2).\n";
}
}

UVA-10789 Prime Frequency

Since every case can only put 2001 size of string, I just pre-calculate every case.(from exist 1 ~ 2001 times).
Then, use map to calculate individual alphabat exist n times, and it will auto sort too.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <bits/stdc++.h>
using namespace std;

#define ll long long

int main()
{
bool nums[2002];
nums[0] = nums[1] = false;
for (int i = 2; i < 2002; i++)
{
nums[i] = true;
for (int j = sqrt(i); j > 1; j--)
if (i % j == 0)
nums[i] = false;
}
int t, n;
cin >> t;
for (int i = 0; i < t; i++)
{
cout << "Case " << i + 1 << ": ";
string s;
cin >> s;
map<char, int> mp;
for (char c : s)
mp[c]++;
bool isEmpty = true;
for (auto it : mp)
if (nums[it.second])
{
isEmpty = false;
if (it.first < 10)
cout << int(it.first);
else
cout << it.first;
}
if (isEmpty)
cout << "empty";
cout << "\n";
}
}

UVA-10903 Rock-Paper-Scissors Tournament

Firstly, I define rock paper scissors to 0,1,2, respectfully. (call it t1, t2, for person 1, 2, respectfully.)
We observed that this game has 3^2 = 9 ways to perform, to get result.
To get result, I use a 3*3 matrix to store result, 1 for win, -1 for loss, 0 for even.
result = pos[t1][t2], so to speak.
Then, I put result into arrays ,and therefore get answers we wanted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;

#define ll long long

int main()
{ // rock scissors paper
map<string, int> mp;
mp["rock"] = 0;
mp["scissors"] = 1;
mp["paper"] = 2;
int pos[3][3] = {{0, 1, -1}, {-1, 0, 1}, {1, -1, 0}};
int n, k;
bool start = true;
while (cin >> n && n)
{
if (start)
start = false;
else
cout << endl;
cin >> k;
int games = k * (n * (n - 1)) / 2;
vector<int> pw(n + 1, 0); // players win times
vector<int> pl(n + 1, 0); // loses
for (int i = 0; i < games; i++)
{
int p1, p2, t1, t2;
string s1, s2;
cin >> p1 >> s1 >> p2 >> s2;
t1 = mp[s1];
t2 = mp[s2];
if (pos[t1][t2] == 0)
continue;
else if (pos[t1][t2] == 1)
pw[p1]++, pl[p2]++;
else if (pos[t1][t2] == -1)
pw[p2]++, pl[p1]++;
}
for (int i = 1; i <= n; i++)
{
if (pw[i] + pl[i] == 0)
cout << "-\n";
else
cout << fixed << setprecision(3) << ((double)pw[i] / (double)(pw[i] + pl[i])) << endl;
}
}
}

UVA-10336 Rank the Languages

This is trying to find numbers of component in a map.
So we apply simply dfs on it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

const int dir[5] = {0, -1, 0, 1, 0};
int m, n;
vector<vector<char>> v;

void dfs(int x, int y)
{
if (v[x][y] == 0)
return;
char val = v[x][y];
v[x][y] = 0;
for (int i = 0; i < 4; i++)
{
int nx = x + dir[i];
int ny = y + dir[i + 1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && v[nx][ny] == val)
dfs(nx, ny);
}
}

int main()
{
int t;
cin >> t;
for (int cnt = 1; cnt <= t; cnt++)
{
cin >> m >> n;
v.resize(m, vector<char>(n));
map<char, int> mp;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
cin >> v[i][j];
int res = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (v[i][j] != 0)
mp[v[i][j]]++, dfs(i, j);
cout << "World #" << cnt << "\n";
vector<pair<int, char>> ans;
for (auto &it : mp)
ans.push_back(make_pair(it.second, it.first));
sort(
ans.begin(), ans.end(), [](const pair<int, char> &it1, const pair<int, char> &it2) -> bool
{
if(it1.first != it2.first)
return it1.first > it2.first;
return it1.second < it2.second; });
for (auto &it : ans)
cout << it.second << ": " << it.first << "\n";
}
}

UVA-11584 Partitioning by Palindrome

same leetcode question: 132. Palindrome Partitioning II

We use Dynamic Programming to address this problem.
That is, dp[i] means from s[0] to s[i-1], the minimum partition.
Therefore, dp[s.size()] or dp.back() is the result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define INF 999999

int main()
{
int t;
cin >> t;
while (t--)
{
string s;
cin >> s;
vector<int> dp(s.size() + 1);
for (int i = 0; i <= s.size(); i++)
dp[i] = i; // that is, dp 1 ~ s.size() is s: 0 ~ s.size()-1
for (int i = 1; i < s.size(); i++)
{
// even numbers of characters kind of palindrome
int x = i - 1, y = i;
while (x >= 0 && y < s.size() && s[x] == s[y])
{
dp[y + 1] = min(dp[y + 1], dp[x] + 1);
x--, y++;
}
// odd
x = y = i;
while (x >= 0 && y < s.size() && s[x] == s[y])
{
dp[y + 1] = min(dp[y + 1], dp[x] + 1);
x--, y++;
}
}
cout << dp.back() << endl;
}
}

UVA-10635 Prince and Princess

A Longest Common Subsequence (LCS) Problem.

Fairly hard problem tho, mainly because it will TLE on the 2d DP solution.

Also, there’s a same problem on leetcode, up and running for those leetcode grinder. By the way, the 2d DP approach will pass on leetcode, and it’s fairly fast on those test case. No wonder it’s mark medium on leetcode. haha.

link: 1143. Longest Common Subsequence

2D DP or DFS + memorization (TLE)

Provide both 2-d Dynamic Programming and dfs solution at lcs().
But It will TLE in the judge, so I will not talk too much in this slope.

Time Complexity : O(n^2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define INF 999999

vector<vector<int>> dp;

int dfs(vector<int> &t1, vector<int> &t2, int x, int y)
{
if (dp[x][y] != -1)
return dp[x][y];
if (x >= t1.size() || y >= t2.size())
return 0;
int y1 = y, x1 = x;
for (; y < t2.size(); y++)
if (t1[x] == t2[y])
break;
if (y >= t2.size())
return 0;
int res = 0;
for (int i = x + 1; i < t1.size(); i++)
res = max(res, dfs(t1, t2, i, y + 1) + 1);
return dp[x1][y1] = res;
}

int lcs(vector<int> &t1, vector<int> &t2)
{
// dfs memoization method
// return dfs(t1, t2, 0, 0) + 1;

// top down dp method
// where dp[x][y] means
for (int x = 0; x < t1.size(); x++)
{
for (int y = 0; y < t2.size(); y++)
{
dp[x][y] = 0;
if (y - 1 >= 0 && x - 1 >= 0)
dp[x][y] = dp[x - 1][y - 1];
if (t1[x] == t2[y])
dp[x][y]++;
else
dp[x][y] = max(x - 1 >= 0 ? dp[x - 1][y] : 0, y - 1 >= 0 ? dp[x][y - 1] : 0);
}
}
return dp[t1.size() - 1][t2.size() - 1];
}

int main()
{
int t;
cin >> t;
for (int tt = 1; tt <= t; tt++)
{
int n, p, q, temp;
cin >> n >> p >> q;
vector<int> t1, t2;
for (int i = 0; i <= p; i++)
{
cin >> temp;
t1.push_back(temp);
}
for (int i = 0; i <= q; i++)
{
cin >> temp;
t2.push_back(temp);
}
dp.assign(t1.size(), vector<int>(t2.size(), -1));
cout << "Case " << tt << ": " << lcs(t1, t2) << endl;
}
}

Method 2 : LCS to LIS

Actually, if you really look into LCS, it can be devide into a LIS, which has a best practice of complexity O(nlgn).

Just like this, where * and x means t1[i] == t2[j].

ref: ntnu algo

But, it just not this case, right?
Since elements in our list is unique, so our thing will not alike some normal LCS graph. Rather, it’s more easy.

According to this rule, we can confidently say that same row or column will have no more than 1 value. Therefore, it reduce the complexity that we don’t have to use pairs… sorting … stuff. All we have to do is:

  1. map t1 value to t1 index.
  2. through t2 iteration, add (if t1 get the same value) it’s t1 index to a vector.
  3. Since vector is already in t2’s iteration, do LIS on vector’s value.

same as the code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define INF 999999

// map t1 sequential index into 1 ~ 62501 (number)
int board[62501];

int lcs(vector<int> &t1, vector<int> &t2)
{
fill(board, board + 62501, -1);
for (int i = 0; i < t1.size(); i++)
board[t1[i]] = i;
vector<int> v;
for (int i = 0; i < t2.size(); i++)
if (board[t2[i]] != -1)
v.emplace_back(board[t2[i]]);
// Then apply LIS on v
vector<int> dp(v.size() + 1, 100000);
for (int i = 0; i < v.size(); i++)
*lower_bound(dp.begin(), dp.end(), v[i]) = v[i];
return lower_bound(dp.begin(), dp.end(), 99999) - dp.begin();
}

int main()
{
int t;
cin >> t;
for (int tt = 1; tt <= t; tt++)
{
int n, p, q, temp;
cin >> n >> p >> q;
vector<int> t1, t2;
for (int i = 0; i <= p; i++)
{
cin >> temp;
t1.push_back(temp);
}
for (int i = 0; i <= q; i++)
{
cin >> temp;
t2.push_back(temp);
}
cout << "Case " << tt << ": " << lcs(t1, t2) << endl;
}
}

Time complexity: O(n*log(n))

Intuition

如果直接建圖會變成multiple source, 不符合dijkstra,所以將sources和destinations都連上node 0 和 node 700,再使用dijkstra演算法,尋找0到700最短路徑。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include <climits>
#include <algorithm>
#include <vector>
#include <string>
#include <cstring>
#include <sstream>
#include <queue>
using namespace std;

#define mp make_pair
#define pr pair<int,int>
#define INF 9999999

vector<vector<pair<int, int>>> edges;
vector<int> T;
priority_queue<pr, vector<pr>, greater<pr>>pq;
vector<int> dis;

void dijkstra() {
dis.assign(701, INF);
dis[0] = 0;
pq.emplace(mp(0, 0));
while (!pq.empty()) {
int x = pq.top().second;
int val = pq.top().first;
pq.pop();
for (auto y : edges[x]) {
//cout << y.first << " ";
if (dis[y.first] > dis[x] + y.second) {
dis[y.first] = dis[x] + y.second;
pq.push(mp(dis[y.first], y.first));
}
}//cout << endl;
}

}

void connect(int x, int y, int cost) {
edges[x].emplace_back(mp(y, cost));
edges[y].emplace_back(mp(x, cost));
}

void print(int x) {
for (auto it : edges[x]) {
cout << it.first << " " << it.second << endl;
}
}

int main() {
int n, k;
while (cin >> n >> k) {
T.assign(n + 1, 0);
edges.assign(701, vector<pair<int, int>>());

for (int i = 1; i <= n; i++)
cin >> T[i];
cin.ignore();
// connect linearly
for (int i = 1; i <= n; i++) {
string s;
getline(cin, s);
stringstream ss(s);
int x, y;
ss >> x;
if (x == 0)
connect(0, 100 * i, 0);
while (ss >> y) {
connect(100 * i + x, 100 * i + y, (y - x) * T[i]);
x = y;
}
}

// connect different -elevator
for (int i = 0; i < 100; i++)
for (int x = 1; x <= n; x++)
for (int y = x + 1; y <= n; y++)
if (!edges[x * 100 + i].empty() && !edges[y * 100 + i].empty())
connect(x * 100 + i, y * 100 + i, 60);
// connect endpoint
for (int x = 1; x <= n; x++)
if (!edges[x * 100 + k].empty())
connect(x * 100 + k, 700, 0);
//print(230);
dijkstra();
if (dis[700] == INF)
cout << "IMPOSSIBLE\n";
else cout << dis[700] << endl;
}
}

DFS, aka. depth-first search, is a nice tool to look data in depth-first manner.
an example to travel through graph will be this :

1
2
3
4
5
6
7
void dfs(Node* u) {
if u is visited:
return;
Visit();
for edges(u,v) connect with node:
dfs(v);
}

Examples:

DFS

UVA - 280 Vertex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define mp make_pair
#define ALL(x) x.begin(), x.end()

const int mod = 1e9 + 7;

vector<vector<int>> ver;
vector<int> vis;

int dfs(int x, int start = 0)
{
if (vis[x])
return 0;
if (!start)
vis[x] = 1;
int res = 1;
for (int i = 0; i < ver[x].size(); i++)
res += dfs(ver[x][i]);
return res;
}

void solve(int v)
{
ver.clear();
ver.resize(v + 1);
int temp, t1;
while (cin >> temp && temp)
{
while (cin >> t1 && t1)
ver[temp].emplace_back(t1);
}
int m;
cin >> m;
for (int i = 0; i < m; i++)
{
vis.clear();
vis.resize(v + 1, 0);
cin >> temp;
cout << v + 1 - dfs(temp, 1);
for (int j = 1; j <= v; j++)
{
if (vis[j] == 0)
cout << " " << j;
}
cout << "\n";
}
}

int main(int argc, const char *argv[])
{
int v;
while (cin >> v && v)
solve(v);
return 0;
}

UVA - 614

HAVE TO USE setw. (very important!!!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//
// main.cpp
// template
//
// Created by Ryan Kert on 2022/10/22.
//
#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define fast \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0)
#define mp make_pair
#define ALL(x) x.begin(), x.end()

const int mod = 1e9 + 7;

int r[6];
int m[12][12];
int vis[12][12];

void draw()
{
cout << "+";
for (int i = 0; i < r[1]; i++)
cout << "---+";
cout << "\n";
for (int i = 0; i < r[0]; i++)
{
cout << "|";
for (int j = 0; j < r[1]; j++)
{
if (vis[i][j] == 0)
cout << " ";
if (vis[i][j] == -1)
cout << "???";
if (vis[i][j] > 0)
cout << setw(3) << vis[i][j];
if (m[i][j] % 2 == 1 || j + 1 == r[1])
cout << "|";
else
cout << " ";
}
cout << "\n+";
for (int j = 0; j < r[1]; j++)
{
if (m[i][j] > 1 || i + 1 == r[0])
cout << "---+";
else
cout << " +";
}
cout << "\n";
}
cout << "\n\n";
}

bool dfs(int x, int y, int ind) // x : row, y : col
{
if (vis[x][y] != 0)
return false;
vis[x][y] = ind++;
if (x == r[4] && y == r[5])
return true;

if (y > 0 && m[x][y - 1] % 2 == 0) // left
if (dfs(x, y - 1, ind))
return true;
if (x > 0 && m[x - 1][y] < 2) // up
if (dfs(x - 1, y, ind))
return true;
if (y + 1 < r[1] && m[x][y] % 2 == 0) // right
if (dfs(x, y + 1, ind))
return true;
if (x + 1 < r[0] && m[x][y] < 2) // down
if (dfs(x + 1, y, ind))
return true;
vis[x][y] = -1;
ind--;
return false;
}

void solve()
{
for (int i = 0; i < r[0]; i++)
for (int j = 0; j < r[1]; j++)
cin >> m[i][j];
memset(vis, 0, sizeof(vis));
for (int i = 2; i < 6; i++)
r[i]--;
dfs(r[2], r[3], 1);
draw();
}

int main(int argc, const char *argv[])
{
fast;
int cnt = 1;
while (cin >> r[0] >> r[1] >> r[2] >> r[3] >> r[4] >> r[5] && r[0])
{
cout << "Maze " << cnt++ << "\n\n";
solve();
}

return 0;
}

UVA - 12442 Forwarding Emails

brute force = TLE
Therefore, we think that if we had traveled the vertex before, we don’t have to travel it again, since if it has been traversed, the traveler is definitely possessed greater reachable person.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//
// main.cpp
// template
//
// Created by Ryan Kert on 2022/10/22.
//
#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define fast \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0)
#define mp make_pair
#define ALL(x) x.begin(), x.end()

const int mod = 1e9 + 7;

int v[50001];
bool vis[50001], dfsV[50001];

int dfs(int i)
{
if (dfsV[i])
return 0;
vis[i] = dfsV[i] = true;
return 1 + dfs(v[i]);
}

void solve()
{
int m;
cin >> m;
memset(v, 0, m + 1);
for (int i = 0; i < m; i++)
{
int ind;
cin >> ind;
cin >> v[ind];
}
int res = 0, idx;
memset(vis, false, m + 1);
for (int i = 1; i <= m; i++)
{
if (!vis[i])
{
memset(dfsV, false, m + 1);
int temp = dfs(i);
if (res < temp)
{
res = temp;
idx = i;
}
}
}
cout << idx << endl;
}

int main(int argc, const char *argv[])
{
fast;
int t;
cin >> t;
for (int i = 0; i < t; i++)
{
cout << "Case " << i + 1 << ": ";
solve();
}

return 0;
}

Build an Blogroll on Hexo Next

Year ago, I saw many blogger collects their friends blog post via Github Action auto run.
Therefore, I always want to try it out.

Anyways, I build it with typescript. Also, if you have any questions or suggestions, any issues or prs are welcomed.

Step1: Generate useful Data from RSS-feed

This project is based on rss feed, so if you or your friend blog doesn’t have /feed, feed.xml, atom.xml, or any kinds of xml file contains your full blogs’ intel, you will have to generate one yourself.

How to use it

  1. Fork this repository

  2. install your friends’ rss pages into this file ./_data/friends.json, in this format:

1
2
3
4
5
6
7
8
[
{
"title": "Ryan's Blog",
"link": "https://blog.ryankert.cc/",
"feed": "https://blog.ryankert.cc/atom.xml"
},
...
]
  1. Until it generate file sussessfully, it will generate a new branch automatically. Then, you setup your github page to display the branch gh-pages.

It will be display at https://<github-username>.github.io/rss-friend/<file>.

There are three file generated

1
2
3
rss.json       // sorted json year, month, day
sorted.json // sorted json universal date ex:2022-08-22T17:47:35.000Z
unsort.json // unsort raw data

Auto Update

at (UTC) 1:00 and 13:00

or at (UTC+8) 9:00 and 21:00

Step2: Hexo settings

Setup blogroll page

  1. in ./source folder, add blogroll/index.md, change <github_username> to your github username.

    index.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
---
title: Friends & Blogroll
date: 2022-08-25 22:59:02
comments: false
---

{% note info %}

#### Welcome to Friends & blog

This place collects my friends & some of the nice blogs of my select.

{% endnote %}

<div class="posts_friends"></div>

<script>
function createElement(elementType, style, link, innerhtml) {
let elementCreated = document.createElement(elementType);
elementCreated.href = link;
elementCreated.innerHTML = innerhtml;
elementCreated.style = style;
return elementCreated;
}

var p_f = document.querySelector('.posts_friends');
const request = 'https://<github_username>.github.io/rss-friend/sorted.json';
let d = new Date();
fetch(request)
.then(response => response.json())
.then(json => {
for(let i = 0; i < json.length; i++) {
let currentItem = document.createElement('div');
d = new Date(json[i].date);
let e;

// date
let monthAppend = d.getMonth()+1;
monthAppend = monthAppend.toString();
monthAppend = monthAppend.length < 2 ? "0" + monthAppend : monthAppend;
let dayAppend = d.getDate();
dayAppend = dayAppend.toString();
dayAppend = dayAppend.length < 2 ? "0" + dayAppend : dayAppend;
let tempAppend = monthAppend + "-" + dayAppend + " ";

let margin = 10;
for (let j = 0; j < tempAppend.length; j++) {
if(tempAppend[j] === '1')
margin += 2;
console.log(margin);
}
let style = "border-bottom: none; opacity: 65%; margin: ";
style += margin.toString() + "px";
e = createElement(
'a',
style,
null,
tempAppend
);
currentItem.appendChild(e);

// title + link
e = createElement('a', null, json[i].link, json[i].title);
currentItem.appendChild(e);


// author + link
e = createElement('a', "opacity: 75%;", json[i].author.link, json[i].author.name);
e.classList.add("e-author");
currentItem.appendChild(e);
p_f.appendChild(currentItem);
}
})
</script>

<style>
.e-author {
position: absolute;
right: 5px;
}

@media screen and (max-width: 760px) {
.e-author {
position: relative;
left: 15px
}
}

</style>
  1. in ./theme/hexo-theme-next/_config.yml, add Blogroll
1
2
3
menu:
...
Blogroll: /blogroll/ || fa fa-blog # add

Debug

visit Hexo Next Docs or email me : ryan@ryankert.cc.