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;
}
posted @ 2020-04-19 17:04  st1vdy  阅读(960)  评论(0编辑  收藏  举报