2019 Multi-University Training Contest 4

2019 Multi-University Training Contest 4

题目链接

A.AND Minimum Spanning Tree

贪心连边即可,对于一个数\(x\),如果其二进制位在低位存在\(0\),那么就连向最小的\(0\)的位置;否则就说明\(x\)\(11111\)这种形式,如果最高位再加一位在题目范围内就连向它;否则连向\(1\)即可。

Code

#include<bits/stdc++.h>
typedef long long ll;
const int MAXN = 2e5 + 5, MAXM = 3e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
using namespace std;
const int oo = (1e9) - (1e6);
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pb push_back
#define RR register
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(v) (v.begin(),v.end())
#define lc(x) c[x][0]
#define rc(x) c[x][1]
typedef long double db;
typedef unsigned int uint;

int t, n;
vector<int> ans;
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> t;
    while (t--) {
        ans.clear();
        cin >> n;
        int m = 1;
        while (m * 2 <= n)m <<= 1;
        int b = 2;
        ll res = 0;
        for (int i = 2; i <= m; i++) {
            if (i > b)b <<= 1;
            bool flag = false;
            for (int j = 0; (1 << j) <= i; j++) {
                if (!(i >> j & 1)) {
                    ans.push_back(1 << j);
                    flag = true;
                    break;
                }
            }
            if (!flag)ans.push_back(b);
        }
        for (int i = m + 1; i <= n; i++) {
            bool flag = false;
            for (int j = 0; (1 << j) <= i; j++) {
                if (!(i >> j & 1)) {
                    ans.push_back(1 << j);
                    flag = true;
                    break;
                }
            }
            if (!flag)ans.push_back(1), res++;
        }
        cout << res << '\n';
        for (int i = 0; i < ans.size(); i++)cout << ans[i] << " \n"[i == ans.size() - 1];
    }
    return 0;
}
D.Divide the Stones

手推\(\frac{n}{k}=1,2,3\)的情况,令\(t=\frac{n}{k}\),构造的时候将\(t\)不断缩小规模就行了。
注意一下特殊情况的判断。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 +5;
int T;
int n, k;
vector <int> v[N];
void solve2(int l, int r) {
    for(int i = 1; i <= k; i++) {
        v[i].push_back(l);
        v[i].push_back(r);
        l++; r--;
    }
}
void solve3(int l, int r) {
    int tot = (1ll * r * (r + 1) / 2) / k;
    for(int i = 1; i <= k; i++) {
        v[i].push_back(r);
        r--;
    }
    int tmp = 1;
    for(int i = 1; i <= k; i++) {
        v[i].push_back(tmp);
        tmp += 2;
        if(tmp > k) tmp = 2;
    }
    for(int i = 1; i <= k; i++) {
        int sz = v[i].size();
        v[i].push_back(tot - v[i][sz - 1] - v[i][sz - 2]);
    }
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> n >> k;
        if((1ll * (n + 1) * n / 2) % k != 0) {
            cout << "no" << '\n';
            continue;
        }
        if(n == k) {
            if(n == 1) cout << "yes" << '\n' << 1 << '\n';
            else cout << "no" << '\n';
            continue;
        }
        for(int i = 1; i <= k; i++) v[i].clear();
        int t = n / k;
        int tmp = t;
        while(tmp > 3) {
            solve2(n - 2 * k + 1, n);
            tmp -= 2;
            n -= 2 * k;
        }
        if(tmp == 3) solve3(1, n);
        else solve2(1, n);
        cout << "yes" << '\n';
        for(int i = 1; i <= k; i++) {
            for(auto x : v[i]) cout << x << ' ';
            cout << '\n';
        }
    }
    return 0;
}
G.Just an Old Puzzle

结论题,跟两种局面下逆序对的奇偶性和行差的奇偶性有关

Code

#include<bits/stdc++.h>
typedef long long ll;
const int MAXN = 2e5 + 5, MAXM = 3e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
using namespace std;
const int oo = (1e9) - (1e6);
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pb push_back
#define RR register
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(v) (v.begin(),v.end())
#define lc(x) c[x][0]
#define rc(x) c[x][1]
typedef long double db;
typedef unsigned int uint;

int t, a;
vector<int> v;
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> t;
    while (t--) {
        v.clear();
        int r = 0;
        for (int i = 1; i <= 4; i++) {
            for (int j = 1; j <= 4; j++) {
                cin >> a;
                if (a)v.push_back(a);
                else r = i;
            }
        }
        r = 4 - r;
        int d = 0;
        for (int i = 0; i < 15; i++) {
            for (int j = i + 1; j < 15; j++) {
                if (v[j] < v[i])d ^= 1;
            }
        }
        r %= 2;
        if (!(d^r))cout << "Yes\n";
        else cout << "No\n";
    }
    return 0;
}
H.K-th Closest Distance

一开始被\(k\)的范围坑了,直接\(T\)飞= =
注意等价条件,如果一个\(p\)\(x\)的距离为第\(k\)大,那么\(|p-x|,|p+x|\)这个区间范围有\(k\)个数。
然后二分就行了。
代码如下:

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int T;
int a[N], b[N];
int n, m;
int rt[N], sum[N * 20], ls[N * 20], rs[N * 20];
int tot;
void build(int &o, int l, int r) {
    o = ++tot;
    sum[o] = 0;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    build(ls[o], l, mid); build(rs[o], mid + 1, r);
}
void insert(int last, int &o, int l, int r, int v) {
    o = ++tot;
    ls[o] = ls[last]; rs[o] = rs[last];
    sum[o] = sum[last] + 1;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(v <= mid) insert(ls[last], ls[o], l, mid, v);
    else insert(rs[last], rs[o], mid + 1, r, v);
}
int query(int last, int o, int l, int r, int L, int R) {
    if(L <= l && r <= R) return sum[o] - sum[last];
    int mid = (l + r) >> 1, ans = 0;
    if(L <= mid) ans += query(ls[last], ls[o], l, mid, L, R);
    if(R > mid) ans += query(rs[last], rs[o], mid + 1, r, L, R);
    return ans;
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> n >> m;
        for(int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i];
        sort(b + 1, b + n + 1);
        int D = unique(b + 1, b + n + 1) - b - 1;
        for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + D + 1, a[i]) - b;
        tot = 0; build(rt[0], 1, D);
        for(int i = 1; i <= n; i++) insert(rt[i - 1], rt[i], 1, D, a[i]);
        int last = 0;
        while(m--) {
            int l, r, p, k; cin >> l >> r >> p >> k;
            l ^= last; r ^= last; p ^= last; k ^= last;
            int L = 0, R = 1e6 + 1, mid;
            while(L < R) {
                mid = (L + R) >> 1;
                int k1 = lower_bound(b + 1, b + n + 1, p - mid) - b;
                int k2 = upper_bound(b + 1, b + n + 1, p + mid) - b - 1;
                if(query(rt[l - 1], rt[r], 1, D, k1, k2) >= k) R = mid;
                else L = mid + 1;
            }
            last = R; cout << last << '\n';
        }
    }
    return 0;
}
J.Minimal Power of Prime

暴力筛去\(4000\)以内的素数,那么最终将\(n\)分解质因子指数和不会超过\(4\)
考虑各种情况的答案,答案为\(4\)时,就是\(p^4\)的形式;答案为\(3\)时,就是\(p^3\);答案为\(2\)时,就是\(p^2q^2\);答案为\(1\)时就是其它情况。
然后对于这三种直接开方判断就行,注意一下顺序就行了。
\(pow\)的时候加个\(round\)会减小误差。
代码如下:

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4001;
bool vis[N];
int prime[N], tot;
void pre() {
    for(int i = 2; i < N; i++) {
        if(!vis[i]) {
            prime[++tot] = i;
            for(int j = i * i; j < N; j += i) vis[j] = 1;
        }
    }
}
int T;
ll n;
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    pre();
    cin >> T;
    while(T--) {
        cin >> n;
        int ans = 100;
        for(int i = 1; i <= tot; i++) {
            if(n % prime[i] == 0) {
                int cnt = 0;
                while(n % prime[i] == 0) cnt++, n /= prime[i];
                if(cnt) ans = min(ans, cnt);
            }
        }
        ll a = round(pow(n, 1 / 4.0));
        ll b = round(pow(n, 1 / 3.0));
        ll c = round(pow(n, 1 / 2.0));
        if(a > 1 && a * a * a * a == n) ans = min(ans, 4);
        else if(b > 1 && b * b * b == n) ans = min(ans, 3);
        else if(c > 1 && c * c == n) ans = min(ans, 2);
        else if(n > 1) ans = 1;
        cout << ans << '\n';
    }
    return 0;
}

转载于:https://www.cnblogs.com/heyuhhh/p/11281642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值