2019 杭电多校 第四场

2019 Multi-University Training Contest 4

补题链接:2019 Multi-University Training Contest 4

1001 AND Minimum Spanning Tree (HDU 6614)

题意

给定一个有 \(N\) 个结点的完全图,编号从 \(1\) 到 \(N\)。结点 \(x\) 与结点 \(y\) \((1\leq x, y\leq N, x \neq y)\) 的边的权值为 \(x\) 与 \(y\) 按位与的值,求该图的最小生成树。

题解

位运算

偶数与 1 按位与的值一定是 0,奇数与 1 按位与的值一定是 1。
因此,让所有的偶数结点与结点 \(1\) 相连即可。
接着连接奇数结点。一个数 \(x\) 与奇数按位与的值为 0,那么奇数二进制表示下中的 1 全部要变成 0。由于结点编号从 \(1\) 到 \(N\),那么结点不能取 \(0\),因此 \(x\) 二进制中至少包含一个 1。为了让 \(x\) 尽可能的小(输出为字典序最小),可以让奇数二进制表示下的从右到左第一个 0 变成 1,如下表所示。

奇数 二进制 \(x\)
3 0011 0100
5 0101 0010
7 0111 1000
9 1001 0010
11 1011 0100
13 1101 0010
15 1111 10000

注意:如果奇数选择的最小结点大于 \(N\),那么让该奇数结点与结点 \(1\) 相连,边的权值为 1。
因此,偶数结点的边权一定为 0,奇数结点如果与偶数结点相连边权为 0,与结点 \(1\) 相连权值为 1,保证总的边权最小,满足最小生成树。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 10;

int ans[maxn];

int main() {
    int T;
    cin >> T;
    while(T--) {
        int n;
        scanf("%d", &n);
        int cnt = 0;
        for(int i = 2; i <= n; ++i) {
            if(i % 2) {
                int tmp = i;
                int s = 0;
                while(tmp & 1) {
                    s++;
                    tmp >>= 1;
                }
                int t = 1 << s;
                if(t > n) {
                    ans[i] = 1;
                    cnt += 1;
                } else {
                    ans[i] = t;
                }
            } else {
                ans[i] = 1;
            }
        }
        printf("%d\n", cnt);
        for(int i = 2; i <= n; ++i) {
            printf("%d", ans[i]);
            printf("%s", i == n? "\n": " ");
        }
    }
    return 0;
}

1003 Divide the Stones (HDU 6616)

题意

给定两个整数 \(n\) 和 \(k\),将 \(1 \sim n\) 的整数分成 \(k\) 组,要求每组中的所有数的和相同且每组的数的个数也相同,求可行解。

题解

思维

分类讨论。

  1. 当 \(n\) 为偶数时,\(n / k\) 也必须是偶数。然后蛇形取法即可。
  2. 当 \(n\) 为奇数时,\(n / k\) 也必须是奇数。\(k = 1\) 时特判。其余情况每组先分 \(3\) 个,剩下的按照第一步的方法即可。

1007 Just an Old Puzzle (HDU 6620)

\(solved\ by\ ch\)

题意

给定 \(4 * 4\) 的方格,包含 \(1\) 到 \(15\) 的数和一个空格。空格可以和上下左右的数字块交换。试求是否能够在 \(120\) 步移动空格使得方格变成图中的目标状态。

题解

逆序数

题目只需考虑是否有解,不需求出移动步数。即判断十五数码问题是否有解。
满足下列条件一定有解。

  1. 若格子列数为奇数,则逆序数必须为偶数;
  2. 若格子列数为偶数,且逆序数为偶数,则当前空格所在行数与初始空格所在行数的差为偶数;
  3. 若格子列数为偶数,且逆序数为奇数,则当前空格所在行数与初始空格所在行数的差为奇数。

参考

数字华容道怎样才能有解

#include <bits/stdc++.h>
using namespace std;
int a[17];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int cnt=0,it;
        for(int i=1;i<=16;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]==0)
            {
                if(i%4==0) it=i/4;
                else it=1+i/4;
            }
        }
        for(int i=2;i<=16;i++)
        {
            if(a[i]==0) continue;
            for(int j=1;j<i;j++)
            {
                if(a[j]>a[i])
                    cnt++;
            }
        }
        //cout<<cnt<<" "<<it<<endl;
        if(cnt%2==0)
        {
            if(abs(4-it)%2==0) printf("Yes\n");
            else printf("No\n");
        }
        else
        {
            if(abs(4-it)%2==0) printf("No\n");
            else printf("Yes\n");
        }
    }
    return 0;
}

1008 K-th Closest Distance (HDU 6621)

\(solved\ by\ ch\)

题意

给定一个 \(a_1 ... a_n\) 的数组。给定 \(m\) 个询问,每个询问包含四个整数 \(L\), \(R\), \(p\), \(K\),求 \(\{|a_L - p|, |a_{L+1} - p|, ... ,|a_R - p|\}\) 中第 \(K\) 大的数。

题解

二分 排序 离散化

记录所有数的下标,对所有数离散化,查找 \(p\) 的位置,往左往右分别找 \(k\) 个数,使得这些数的下标在区间 \([L, R]\) 内,对所有找到的数排序,第 \(k\) 大的数即是答案。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef struct DATE
{
    int id, val;
} D;
D date[100010];
bool cmp1(D a, D b)
{
    return a.val < b.val;
}
vector<int> id[100010];
int a[100010];
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        memset(a, 0, sizeof(a));
        int n, m, num = 0, Xor = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            date[i].id = i;
            scanf("%d", &date[i].val);
        }
        sort(date + 1, date + n + 1, cmp1);
        for (int i = 1; i <= n; i++)
        {
            if (a[num] != date[i].val)
                a[++num] = date[i].val;
            id[num].push_back(date[i].id);
        }
        for (int i = 1; i <= num; i++)
        {
            sort(id[i].begin(), id[i].end());
        }
        for (int i = 0; i < m; i++)
        {
            int l, r, L, R, it, p, k, x[1010], tmp = 0;
            scanf("%d%d%d%d", &l, &r, &p, &k);
            l ^= Xor, r ^= Xor, k ^= Xor, p ^= Xor;
            it = lower_bound(a + 1, a + num + 1, p) - a;
            int tmp1 = 0, tmp2 = 0;
            for (int j = it - 1; j >= 1 && tmp1 <= k; j--)
            {
                L = lower_bound(id[j].begin(), id[j].end(), l) - id[j].begin();
                while (L < id[j].size() && id[j][L] <= r)
                {
                    x[tmp++] = abs(a[j] - p);
                    L++;
                    tmp1++;
                    if (tmp1 > k)
                        break;
                }
            }
            for (int j = it; j <= num && tmp2 <= k; j++)
            {
                L = lower_bound(id[j].begin(), id[j].end(), l) - id[j].begin();
                while (L < id[j].size() && id[j][L] <= r)
                {
                    x[tmp++] = abs(a[j] - p);
                    L++;
                    tmp2++;
                    if (tmp2 > k)
                        break;
                }
            }
            sort(x, x + tmp);
            Xor = x[k - 1];
            printf("%d\n", x[k - 1]);
        }
        for (int i = 1; i <= num; i++)
            id[i].clear();
    }
    return 0;
}

1010 Minimal Power of Prime (HDU 6623)

题意

给定一个整数 \(n > 1\),分解质因数后,求最小的指数。

题解

素数筛 质因数分解

由于 \(3982^4 > 10^{18}\),那么所有大于 \(3982\) 的数的指数最多为 \(4\)。
先筛出 \(4000\) 以内的所有质数,将 \(n\) 暴力分解质因数。如果 \(n\) 还没分解完,那么剩下的数分解质因数后的指数只能是 \(1\) 到 \(4\) 之间,从大到小枚举即可。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

ll n;
int ans;

vector<int> primes;
int is_prime[4000];

void sieve() {
    is_prime[0] = is_prime[1] = 1;
    for(int i = 2; i < 4000; ++i) {
        if(!is_prime[i]) {
            primes.push_back(i);
        }
        for(int j = 0; j < primes.size() && i * primes[j] < 4000; ++j) {
            is_prime[i * primes[j]] = 1;
            if(i % primes[j] == 0) break;
        }
    }
}

void solve() {
    for(int i = 0; i < primes.size() && primes[i] * primes[i] <= n; ++i) {
        int cnt = 0;
        if(n % primes[i] == 0) {
            while(n % primes[i] == 0) {
                cnt++;
                n /= primes[i];
            }
            ans = min(ans, cnt);
        }
    }
    if(n == 1 || ans == 1) {
        printf("%d\n", ans);
        return;
    }
    int flag = 0;
    for(int i = 4; i >= 2; --i) {
        ll num = pow(n, 1.0 / i);
        for(ll j = num - 3; j < num + 3; ++j) {
            ll res = 1;
            for(int k = 0; k < i; ++k) res *= j;
            if(res == n) {
                flag = 1;
                break;
            }
        }
        if(flag) {
            ans = min(ans, i);
            break;
        }
    }
    if(flag) {
        printf("%d\n", ans);
    } else {
        printf("1\n");
    }
}

int main() {
    sieve();
    // for(int i = 0; i < 30; ++i) cout << primes[i] << endl;
    int T;
    scanf("%d", &T);
    while(T--) {
        ans = 65;
        scanf("%lld", &n);
        solve();
        // printf("%d\n", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wulitaotao/p/11428308.html

时间: 2024-11-06 21:32:52

2019 杭电多校 第四场的相关文章

2019杭电多校第四场hdu6621 K-th Closest Distance(二分答案+主席树)

K-th Closest Distance 题目传送门 解题思路 二分答案+主席树 先建主席树,然后二分答案mid,在l和r的区间内查询[p-mid, p+mid]的范围内的数的个数,如果大于k则说明这个范围内存在第k小的数,r=mid,否则不存在,l=mid+1. 代码如下 #include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; inline int read(){

2019 杭电多校 第五场

2019 Multi-University Training Contest 5 补题链接:2019 Multi-University Training Contest 5 罚时爆炸 自闭场 1004 equation (HDU 6627) 题意: 给定一个整数 \(C\) 和 \(N\) 组 \(a_i,b_i\),求 \(∑_{i=1}^N|a_i\cdot x + b_i| = C\) 的所有解,如果有无穷多个解就输出 -1. 思路 分类讨论 分类讨论去绝对值.根据 \(b_i / a_i

2019 杭电多校 第七场

2019 Multi-University Training Contest 7 补题链接:2019 Multi-University Training Contest 7 1001 A + B = C 题意: 给出 \(a, b, c\),求 \(x, y, z\) 满足 \(a\cdot 10^x + b\cdot 10^y = c\cdot 10^z\).\(a, b, c \le 10^{100000}\). 题解: 补零到 \(a, b, c\) 长度相等之后,可能的情况只有四种: \

2019 杭电多校 第八场

2019 Multi-University Training Contest 8 补题链接:2019 Multi-University Training Contest 8 1003 Acesrc and Good Numbers HDU 6659 题意 定义 \(f(d, n)\) 为十进制下 \(1\) 到 \(n\) 所有数的数位中数字 \(d\) 出现的次数.给定 \(x\),找出最大的 \(n(n \le x)\) 满足 \(f(d, n) = n\). 题解 看到了一个神仙做法. 显

2019 杭电多校 第六场

2019 Multi-University Training Contest 6 补题链接:2019 Multi-University Training Contest 6 1002 Nonsense Time (HDU 6635) 题意 给定包含 \(n\) 个不同数字的排列 \(p\).一开始所有数字都冻住.再给出一个长度为 \(n\) 的数组 \(k\),\(k[i]\) 表示 \(p[k[i]]\) 在第 \(i\) 时刻解冻.输出 \(n\) 个数,表示第 \(i\) 个时刻数组 \(

2019 杭电多校 第三场

2019 Multi-University Training Contest 3 补题链接:2019 Multi-University Training Contest 3 1002 Blow up the city (HDU-6604) 题意 给定 \(n\) 个点和 \(m\) 条边的有向无环图,给出 \(q\) 次询问,每个询问给出 \(a\) 和 \(b\),求有多少个点,满足该点删去后 \(a\) 和 \(b\) 中至少一个点不能到达出度为 \(0\) 的点. 题解 支配树/灭绝树 拓

2019杭电多校第三场 1004 Distribution of books

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6606 考虑二分答案,我们二分一个值\(x\),那么要怎么来验证这个答案是否可行,考虑dp求解,设\(dp[i]\)为前i个在答案为\(x\)的情况下划分最最多组数,那么若\(dp[n] \geq k\) 则这个x可行, 很显然可以看出\(x\)是单调的,所以二分. \[dp[i] = max(dp[j]) + 1 (sum[i] - sum[j-1] \leq x)\] 如果直接采用暴力枚举的话复杂

2019杭电多校第三场 1008 K-th Closest Distance

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6621 考虑主席树,我们先将所有值离散化之后建主席树.对于每个查询\(s,t,p,k\) 我们考虑二分一个值\(mid\),考虑当前区间内,\([p-mid, p+mid]\)的值有多少个,很显然这是符合单调性的,那么我们只需要每次判断即可.时间复杂度\(O(nlog^2n)\) #include <bits/stdc++.h> #define pii pair<int, int> #d

2019杭电多校第六场hdu6638 Snowy Smile(线段树+枚举)

Snowy Smile 题目传送门 解题思路 先把y离散化,然后把点按照x的大小进行排序,我们枚举每一种x作为上边界,然后再枚举其对应的每一种下边界.按照这种顺序插入点,这是一个压维的操作,即在线段树中的y位置加上其w,并利用线段树来更新动态的最大子段和. 代码如下 #include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 2005; stru