2019 JUST Programming Contest题解
2019 JUST Programming Contest题解
A. On the Road to Happiness
队友写的,听说是边双。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int maxm = maxn << 2;
int head[maxn], tot;
struct Edge {
int v;
int w;
int next;
} edge[maxm << 1];
inline void AddEdge(int u, int v, int w)
{
edge[++tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot;
}
int col[maxn];
namespace Tarjan {
int dfn[maxn], low[maxn], dfs_num;
int col_num;
int stack[maxn], top;
void dfs(int now, int fa)
{
dfn[now] = low[now] = ++dfs_num;
stack[++top] = now;
for (int i = head[now]; i; i = edge[i].next) {
if (!dfn[edge[i].v]) {
dfs(edge[i].v, now);
low[now] = min(low[now], low[edge[i].v]);
}
else if (edge[i].v != fa)
low[now] = min(low[now], dfn[edge[i].v]);
}
if (dfn[now] == low[now]) {
++col_num;
int j;
do {
j = stack[top--];
col[j] = col_num;
} while (j != now);
}
}
int Tarjan(int n)
{
memset(dfn, 0, sizeof(dfn));
dfs_num = col_num = top = 0;
for (int i = 1; i <= n; i++)
if (!dfn[i])
dfs(i, 0);
return col_num;
}
}
typedef pair<int, int> pii;
vector<pii> E[maxn];
char s[maxn];
int cnt[maxn];
typedef long long LL;
LL ans = 0;
int dfs(int now, int fa)
{
int num = cnt[now];
for (auto it : E[now]) {
if (it.first == fa)
continue;
int k = dfs(it.first, now);
num += k;
//printf("(%d,%d)\n", k, it.second);
ans = ans + LL(abs(k)) * it.second;
}
return num;
}
int main()
{
int t;
scanf("%d", &t);
while (t--) {
int n, m;
scanf("%d%d", &n, &m);
scanf("%s", s + 1);
tot = 0;
memset(head, 0, sizeof(head));
int u, v, w;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
AddEdge(u, v, w);
AddEdge(v, u, w);
}
Tarjan::Tarjan(n);
// for (int i = 1; i <= n; i++)
// printf("%d ", col[i]);
// printf("\n");
for (int i = 1; i <= n; i++)
E[i].clear();
for (int i = 1; i <= n; i++) {
for (int j = head[i]; j; j = edge[j].next) {
if (col[i] != col[edge[j].v])
E[col[i]].push_back(make_pair(col[edge[j].v], edge[j].w));
}
}
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++)
if (s[i] == 'A')
cnt[col[i]]--;
else if (s[i] == 'H')
cnt[col[i]]++;
ans = 0;
dfs(1, 0);
printf("%lld\n", ans);
}
return 0;
}
B. Memory Management System
队友说是区间求最值水题。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
bool vis[maxn];
int a[maxn];
int Log[maxn];
void init()
{
Log[0] = -1;
for (int i = 1; i < maxn; i++)
Log[i] = ((i & (i - 1)) == 0) ? Log[i - 1] + 1 : Log[i - 1];
}
int dp[maxn][20];
void RMQ(int n)
{
for (int i = 1; i <= n; i++)
dp[i][0] = a[i];
int Lg = Log[n];
for (int i = 1; i <= Lg; i++) {
for (int j = 1; j <= n - (1 << i) + 1; j++) {
dp[j][i] = max(dp[j][i - 1], dp[j + (1 << (i - 1))][i - 1]);
}
}
}
int LCP(int left, int right)
{
int base = Log[right - left + 1];
return max(dp[left][base], dp[right + 1 - (1 << base)][base]);
}
int main()
{
init();
int t;
scanf("%d", &t);
while (t--) {
int n, m, q;
scanf("%d%d%d", &n, &m, &q);
fill(vis, vis + 1 + m, false);
fill(a, a + 1 + m, 0);
int u, v;
for (int i = 1; i <= n; i++) {
scanf("%d%d", &u, &v);
for (int j = u; j <= v; j++)
vis[j] = true;
}
for (int i = 1; i <= m;) {
if (vis[i]) {
i++;
continue;
}
int cnt = 1;
while (++i <= m && !vis[i])
cnt++;
a[cnt] = max(a[cnt], i - 1);
}
// for (int i = 1; i <= m; i++)
// printf("(%d,%d)", i, a[i]);
// printf("\n");
RMQ(m);
int k;
while (q--) {
scanf("%d", &k);
int stdr = LCP(k, m);
if (stdr == 0) {
printf("-1 -1\n");
} else {
printf("%d %d\n", stdr - k + 1, stdr);
}
}
}
return 0;
}
C. Large GCD
题意:求 \(gcd(5^n+7^n,5^m+7^m)\) ,其中 \(gcd(n,m)=1\) 。
分析:找规律自然是第一选择,不难发现当 \(n\) 或 \(m\) 其中至少一个数字为偶数时结果为 \(2\) ,否则为 \(12\) 。
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma comment(linker, "/stack:200000000")
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int t; cin >> t;
while (t--) {
int n, m; cin >> n >> m;
if (n % 2 == 0 || m % 2 == 0) cout << "2\n";
else cout << "12\n";
}
}
D. XOR Permutations
队友秒了。
#include<bits/stdc++.h>
#define ll long long
#define maxn 10010
#define mod 998244353
using namespace std;
char a[20];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int a1 = 0, a2 = 0, b1 = 0, b2 = 0, c1 = 0, c2 = 0;
scanf("%s", a);
for (int i = 0; i < 10; i++) {
if (a[i] == '0') a2++;
else a1++;
}
scanf("%s", a);
for (int i = 0; i < 10; i++) {
if (a[i] == '0') b2++;
else b1++;
}
scanf("%s", a);
for (int i = 0; i < 10; i++) {
if (a[i] == '0') c2++;
else c1++;
}
for (int z = 0; z < 10; z++) {
if (a1 < b1) {
swap(a1, b1);
swap(a2, b2);
}
if (b1 < c1) {
swap(c1, b1);
swap(c2, b2);
}
if (a1 < b1) {
swap(a1, b1);
swap(a2, b2);
}
// printf("%d %d %d___\n",a1,b1,c1);
if (a1 && b2 && c2) {
a1--, b2--, c2--;
printf("1");
}
else if (a1 && b1 && c1) {
a1--, b1--, c1--;
printf("1");
}
else {
printf("0");
}
}
printf("\n");
}
return 0;
}
E. Building Strings
队友秒了。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0X3f3f3f3f;
const int maxn = 1005;
char s[maxn], p[maxn], a[maxn];
int v[30];
int main()
{
int t;
scanf("%d", &t);
while (t--) {
int n, m;
scanf("%d%d", &n, &m);
scanf("%s%s%s", s + 1, p + 1, a + 1);
memset(v, 0X3f, sizeof(v));
for (int i = 1; i <= n; i++)
v[s[i] - 'a'] = min(v[s[i] - 'a'], p[i] - '0');
LL ans = 0;
for (int i = 1; i <= m; i++)
ans = ans + v[a[i] - 'a'];
if (ans >= inf)
printf("-1\n");
else
printf("%lld\n", ans);
}
return 0;
}
F. camelCase;
队友秒了。
#include<bits/stdc++.h>
#define ll long long
#define maxn 10010
#define mod 998244353
using namespace std;
char a[110];
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%s", a);
if (a[0] >= 'A' && a[0] <= 'Z') {
printf("NO\n");
continue;
}
int n = strlen(a);
int cnt = 0;
for (int i = 0; i < n; i++) {
if (a[i] >= 'A' && a[i] <= 'Z') cnt++;
}
if (cnt <= 6) printf("YES\n");
else printf("NO\n");
}
return 0;
}
G. The Special King
队友秒了。
#include<bits/stdc++.h>
#define ll long long
#define maxn 10010
#define mod 998244353
using namespace std;
int main() {
int t, a, b, c, d;
scanf("%d", &t);
while (t--) {
scanf("%d%d%d%d", &a, &b, &c, &d);
printf("%d\n", abs(a - c) + abs(b - d));
}
return 0;
}
H. The Universal String
题意:判断给出的字符串是否是一个无限循环字符串的子串。
分析:\(O(n)\) 遍历判就行。
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma comment(linker, "/stack:200000000")
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int t; cin >> t;
while (t--) {
string s; cin >> s;
vector<int> a(s.length());
for (int i = 0; i < s.length(); ++i) a[i] = (s[i] - 'a') % 26;
bool f = true;
for (int i = 1; i < s.length(); ++i) {
if (a[i] == 0) {
if (a[i - 1] != 25) f = false;
else continue;
}
if (a[i] != a[i - 1] + 1) f = false;
if (!f) break;
}
cout << (f ? "YES\n" : "NO\n");
}
}
I. Array Negations
队友秒了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 5;
int a[maxn];
int main()
{
int t;
scanf("%d", &t);
while (t--) {
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n && k; i++)
if (a[i] < 0)
a[i] = -a[i],
k--;
else
break;
if (k && (k & 1)) {
sort(a + 1, a + 1 + n);
a[1] = -a[1];
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans += a[i];
printf("%d\n", ans);
}
return 0;
}
J. Grid Beauty
题意:给定一个 \(n\times m\) 的矩阵,你可以重新排列每一行中元素的位置,询问最多有几对数对满足 \(a_{ij}=a_{i-1j}\) ,即上下相邻两个数字相等。
分析:每一行都是独立的,我们直接对每一行贪心匹配就行。
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma comment(linker, "/stack:200000000")
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int t; cin >> t;
while (t--) {
int n, m; cin >> n >> m;
vector<vector<int> > a(n, vector<int>(m, 0));
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
cin >> a[i][j];
ll ans = 0;
for (int i = 0; i < n - 1; ++i) {
map<int, int> MP;
for (int j = 0; j < m; ++j) ++MP[a[i][j]];
for (int j = 0; j < m; ++j) {
if (MP[a[i + 1][j]]) {
++ans;
--MP[a[i + 1][j]];
}
}
}
cout << ans << '\n';
}
}
K. Subarrays OR
题意:给定一个数组 \(a_n\) 求该数组中共有几个不同的区间或值。\([l,r]\) 范围内的区间或指的是 \(a_l\ or\ a_{l+1}\ or\cdots or\ a_r\) 。
分析:考虑到或运算是不减的,因此每次或运算结束后如果产生了一个新的数字,那么至少某一位加了一。由这个观察,我们发现,如果我们考虑 \(O(n^2)\) 的枚举,固定左端点,然后一路向右取或,那么能够产生的不同数字其实并不是 \(n\) 个,而是 \(\log_2{1e9}\) 个,因为数据范围小于 \(1e9\) ,所以二进制数位最大为 \(\log_2{1e9}\) ,也就是我们能够产生的最多的新数了。所以本题的答案上限是 \(\log_2{1e9}\times n\) ,因此本题可以暴力解决。
我们维护一个 \(set\) ,每次把新数和原本就在 \(set\) 中的数取或后再加入,重复这一过程。时间复杂度上限为 \(O(n\log n\log 1e9)\) 。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn];
set<int> x, y, ans;
int main()
{
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
x.clear();
y.clear();
ans.clear();
for (int i = 1; i <= n; i++) {
set<int>& pre = (i & 1 ? x : y);
set<int>& now = (i & 1 ? y : x);
now.clear();
now.insert(a[i]);
for (auto it : pre)
now.insert(it | a[i]);
for (auto it : now)
ans.insert(it);
}
printf("%d\n", (int)ans.size());
}
return 0;
}
L. Median
题意:给定一个 \(n\times m\) 的矩阵矩阵中的元素为 \(\{1,2,3,\cdots,nm\}\) 的集合,寻找所有大小为 \(h\times w\) 的子矩阵中中位数的最小值。
分析:二分答案,然后 \(O(n^2)\) \(check\) ,设我们 \(check\) 的值为 \(x\) ,然后将所有大于 \(x\) 的值置为 \(1\) 否则置为 \(0\) ,然后求一个二维前缀和就能 \(O(n^2)\) 判断了,判定条件是子矩阵之和是否小于等于 \(\frac{hw}{2}\)。
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma comment(linker, "/stack:200000000")
#include <bits/stdc++.h>
#define ll long long
#define SIZE 1010
using namespace std;
int n, m, h, w, num;
int a[SIZE][SIZE], pre[SIZE][SIZE];
void init(int x) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i][j] > x) pre[i][j] = 1;
else pre[i][j] = 0;
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
pre[i][j] += pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1];
}
}
}
bool check(int x) {
init(x);
for (int i = 1; i <= n - h + 1; ++i) {
for (int j = 1; j <= m - w + 1; ++j) {
int x = i + h - 1, y = j + w - 1;
if (pre[x][y] - pre[i - 1][y] - pre[x][j - 1] + pre[i - 1][j - 1] <= num) return true;
}
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> m >> h >> w;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> a[i][j];
}
}
int L = 1, R = n * m, mid, ans;
num = (h * w) >> 1;
while (R >= L) {
mid = (L + R) >> 1;
if (check(mid)) ans = mid, R = mid - 1;
else L = mid + 1;
}
cout << ans;
}