• 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)
    ", 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("
    ");
    
    		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
    ", 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("
    ");
    
            RMQ(m);
    
            int k;
            while (q--) {
                scanf("%d", &k);
                int stdr = LCP(k, m);
                if (stdr == 0) {
                    printf("-1 -1
    ");
                } else {
                    printf("%d %d
    ", 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
    ";
    		else cout << "12
    ";
    	}
    }
    

    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___
    ",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("
    ");
    	}
    	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
    ");
            else
                printf("%lld
    ", 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
    ");
    			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
    ");
    		else printf("NO
    ");
    	}
    	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
    ", 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
    " : "NO
    ");
    	}
    }
    

    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
    ", ans);
        }
    
        return 0;
    }
    

    J. Grid Beauty

    题意:给定一个 (n imes 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 << '
    ';
    	}
    }
    

    K. Subarrays OR

    题意:给定一个数组 (a_n) 求该数组中共有几个不同的区间或值。([l,r]) 范围内的区间或指的是 (a_l or a_{l+1} orcdots or a_r)

    分析:考虑到或运算是不减的,因此每次或运算结束后如果产生了一个新的数字,那么至少某一位加了一。由这个观察,我们发现,如果我们考虑 (O(n^2)) 的枚举,固定左端点,然后一路向右取或,那么能够产生的不同数字其实并不是 (n) 个,而是 (log_2{1e9}) 个,因为数据范围小于 (1e9) ,所以二进制数位最大为 (log_2{1e9}) ,也就是我们能够产生的最多的新数了。所以本题的答案上限是 (log_2{1e9} imes n) ,因此本题可以暴力解决。

    我们维护一个 (set) ,每次把新数和原本就在 (set) 中的数取或后再加入,重复这一过程。时间复杂度上限为 (O(nlog nlog 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
    ", (int)ans.size());
        }
    
        return 0;
    }
    

    L. Median

    题意:给定一个 (n imes m) 的矩阵矩阵中的元素为 ({1,2,3,cdots,nm}) 的集合,寻找所有大小为 (h imes 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;
    }
    
  • 相关阅读:
    小节 +三元表达式
    continue
    break
    flag标签
    #region #endregion
    for 循环
    do while 有例句体会循环的真正原理
    while 循环
    前缀和与差分
    递归的循环实现
  • 原文地址:https://www.cnblogs.com/st1vdy/p/12732314.html
Copyright © 2020-2023  润新知