【第五届武汉纺织大学ACM程序设计竞赛(同步赛)】题解

A. 广告位招租中

Solution

首先数组内一定只要留下 a i ⩾ m a_i \geqslant m aim a i a_i ai,然后开一个数组 v i s vis vis 记录一下 [ 1 , max ⁡ ( a ) ] [1,\max(a)] [1,max(a)] 每个位置有多少数。

考虑枚举最大公约数 g ∈ [ m , max ⁡ ( a ) ] g \in [m, \max(a)] g[m,max(a)],接着我们只要枚举 g g g 的倍数即可。对于 x = y ⋅ g x = y \cdot g x=yg x x x 是数组 a a a 中出现过的,我们要把这些 y y y gcd ⁡ \gcd gcd,看最终是否是 1 1 1,如果是说明这些数的 gcd ⁡ \gcd gcd g g g,否则是 g g g 的倍数。

这样的总时间复杂度是 O ( m l o g m ) O(mlogm) O(mlogm)

C++ Code

#include <bits/stdc++.h>

using i64 = int64_t;
using u64 = uint64_t;
using f64 = double_t;
using i128 = __int128_t;

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cout << std::fixed << std::setprecision(12);
	
    int n, m;
    std::cin >> n >> m;
    
    int max = 0;
    std::vector<int> a;
    for (int i = 0; i < n; i += 1) {
   
        int x;
        std::cin >> x;
        if (x >= m) {
   
            a.push_back(x);
            max = std::max(max, x);
        }
    }
    if (a.empty()) {
   
        std::cout << "0 0\n";
        return 0;
    }
    std::vector<int> vis(max + 1);
    for (int x: a) {
   
        vis[x] += 1;
    }
    int k = 0, ans = 0;
    for (int g = m; g <= max; g += 1) {
   
        int cnt = 0;
        int d = 0;
        for (int x = g, y = 1; x <= max; x += g, y += 1) {
   
            if (vis[x]) {
   
                cnt += vis[x];
                d = std::gcd(d, y);
            }
        }
        if (d == 1 and k < cnt) {
   
            k = cnt;
            ans = g;
        }
    }
    std::cout << k << " " << ans << "\n";
    
    return 0;
}

B. MEX of MEXes

Solution

首先,特判长度为 1 1 1 的排列,此时子数组只有 1 1 1,所以 b b b 中只有 2 2 2,答案为 1 1 1

n > 1 n > 1 n>1 的排列 a a a,我们考虑 b b b 中是否可能出现 v ∈ [ 1 , n ] v \in [1, n] v[1,n]。对于一个确定的 v v v,如果 < v < v <v 的数都在 v v v 的一侧,说明可以选择 1 ,   2 ,   ⋯   ,   v − 1 1, \ 2,\ \cdots, \ v - 1 1, 2, , v1,而不选到 v v v,这样就产生了一个 m e x = v mex = v mex=v 的子数组;否则,只要想选全 1 ,   2 ,   ⋯   ,   v − 1 1, \ 2,\ \cdots, \ v - 1 1, 2, , v1,就一定会选到 v v v,导致没有任何一个子数组的 m e x mex mex v v v

因此我们只要用树状数组计算每个数左右各有多少数小于它,然后从 v = 1 v = 1 v=1 开始枚举到 n n n,看是否存在一个 v v v 无法成为 m e x mex mex

但是特别注意,如果枚举完了 n n n 个数都满足条件,说明此时整个数组 a a a m e x = n + 1 mex = n + 1 mex=n+1,所以答案应该是 n + 2 n + 2 n+2

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

C++ Code

#include <bits/stdc++.h>

using i64 = int64_t;
using u64 = uint64_t;
using f64 = double_t;
using i128 = __int128_t;

template<class T>
struct BIT {
   
    int n, down;
    std::vector<T> a;
    BIT(int _n = 0): down(0) {
   
        init(_n);
    }
    BIT(std::vector<int> _a, int op): down(0) {
   
    	init(_a, op);
    }
    void init(int _n) {
   
        n = _n;
        a.assign(n, T{
   });
    }
    void init(std::vector<int> _a, int op) {
   
    	assert(op == 0 or op == 1);
    	if (op == 0) {
   
    		init(_a.size());
    		for (int i = 0; i < _a.size(); i += 1) {
   
    			add(i, _a[i]);
    		}
    	} else {
   
    		int max = *std::max_element(_a.begin(), _a.end());
	    	int min = *std::min_element(_a.begin(), _a.end());
	    	init(max - min + 1);
	    	for (int x: _a) {
   
	    		add(x - min, 1);
	    	}
	    	down = min;
    	}
    }
    int lowbit(int x) {
   
    	return x & -x;
    }
    void add(int x, const T &v) {
   
        for (int i = x + 1; i <= n; i += lowbit(i)) {
   
            a[i - 1] = a[i - 1] + v;
        }
    }
    void clear() {
   
    	a.assign(n, T{
   });
    }
    T sum(int x) {
   
        T ans{
   };
        for (int i = x; i > 0; i -= lowbit(i)) {
   
            ans = ans + a[i - 1];
        }
        return ans;
    }
    T sum(int l, int r) {
   
        return sum(r) - sum(l);
    }
    int kth(const T &k) {
   
        int x = 0;
        T cur{
   };
        for (int i = 1 << std::__lg(n); i; i /= 2) {
   
            if (x + i <= n and cur + a[x + i - 1] <= k) {
   
                x += i;
                cur = cur + a[x - 1];
            }
        }
        return x;
    }
};

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cout << std::fixed << std::setprecision(12);
	
    int n;
    std::cin >> n;
    
    if (n == 1) {
   
        std::cout << 1 << "\n";
        return 0;
    }
    std::vector<int> a(n), pos(n);
    for (int i = 0; i < n; i += 1) {
   
        std::cin >> a[i];
        pos[--a[i]] = i;
    }
    BIT<int> bit(n);
    std::vector<int> pre(n);
    for (int i = 0; i < n; i += 1) {
   
        pre[a[i]] = bit.sum(a[i]);
        bit.add(a[i], 1);
    }
    bit.clear();
    std::vector<int> suf(n);
    for (int i = n - 1; i >= 0; i -= 1) {
   
        suf[a[i]] = bit.sum(a[i]);
        bit.add(a[i], 1);
    }
    for (int v = 0; v < n; v += 1) {
   
        if (pre[v] > 0 and pre[v] < v or suf[v] > 0 and suf[v] < v) {
   
            std::cout << v + 1 << "\n";
            return 0;
        }
    }
    std::cout << n + 2 << "\n";
    
    return 0;
}

C. 战斗时回复

Solution

把时间拉长到两个时间最小公倍数,然后比较二者的大小即可。

C++ Code

#include <bits/stdc++.h>

using i64 = int64_t;
using u64 = uint64_t;
using f64 = double_t;
using i128 = __int128_t;

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cout << std::fixed << std::setprecision(12);
	
    int T, H, t, n;
    std::cin >> T >> H >> t >> n;
    
    i64 lcm = std::lcm(1LL * T, 1LL * t);
    i64 H1 = lcm / T * H;
    i64 n1 = lcm / t * n;
    
    std::cout << (H1 >= n1 ? "kirito": "hangeki");
    
    return 0;
}

D. 小太阳的帕鲁世界1

Solution

我们直接从终点 ( n , m ) (n, m) (n,m) 逆向搜索即可,只是要特别注意,它对方向的要求是进来的,而我们是回去的,所以要反一下,比如说 g [ i ] [ j ] = D g[i][j] = D g[i][j]=D,正着走是 x = x + 1 x = x + 1 x=x+1,所以反着就是 x = x − 1 x = x - 1 x=x1

时间复杂度 O ( n m ) O(nm)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值