2019年杭电多校第四场

1001 AND Minimum Spanning Tree(HDU6614)

题意

要你构造一棵最小生成树,边权是两顶点的编号的与值。

思路

对于\(2^i-1\)\(2^i\)是否小于等于\(n\),如果是则与\(2^i\)连边,其他的数则看其二进制下最后一个\(0\)在哪,假设是在\(x\),那么就与\(2^x\)连边。

代码实现如下:

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 1000000 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int t, n;
vector<int> vec;

int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        int ans = 0;
        vec.clear();
        for(int i = 2; i <= n; ++i) {
            int num = 0;
            for(int j = 0; j <= 20; ++j) {
                if(i <= (1<<j)) {
                    num = (1<<j);
                    break;
                }
            }
            if(i == num - 1) {
                if(num <= n) vec.push_back(num);
                else vec.push_back(1), ++ans;
            } else {
                for(int j = 0; j <= 20; ++j) {
                    if(!(i & (1<<j))) {
                        vec.push_back((1<<j));
                        break;
                    }
                }
            }
        }
        printf("%d\n", ans);
        int flag = 0;
        for(int i = 0; i < vec.size(); ++i) {
            if(flag) printf(" ");
            flag = 1;
            printf("%d", vec[i]);
        }
        printf("\n");
    }
    return 0;
}

1003 Divide the Stones(HDU6616)

题意

要你把个石子分成\(k\)堆,每堆有\(\frac{n}{k}\)个石子,使得这\(k\)堆石子重量相同,每个石子的重量为\(i\)

思路

对于\(\frac{n}{k}\)偶数我们发现蛇形填数是可以使得其相等的,那么对于奇数我们只需要拿出前\(3k\)个来填,剩余的按照偶数的进行处理即可。

奇数的时候我们首先确定第一列分别为\(1\)~\(k\),第二列肯定要错位填数,通过计算可以得到第\(\frac{k}{2}+1\)\(2k\),然后\(\frac{k}{2}+2\)\(1\),以此类推。第三列则用\(\frac{3(3*k+1)}{3}\)来减即可。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 1000000 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int t, n, k;

int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &k);
        if(1LL * n * (n + 1) / 2 % k || (n == k && n != 1)) {
            printf("no\n");
            continue;
        }
        printf("yes\n");
        int x = k, y = n / k;
        int mp[x+5][y+5];
        if(y & 1) {
            for(int i = 1; i <= x; ++i) mp[i][1] = i;
            mp[k/2+1][2] = 2 * k;
            for(int i = k / 2 + 2; i <= x; ++i) mp[i][2] = i - k / 2 - 1 + k;
            for(int i = 1; i <= k / 2; ++i) mp[i][2] = k + k / 2 + i;
            for(int i = 1; i <= x; ++i) mp[i][3] = 4 * k + k / 2 + 2 - mp[i][1] - mp[i][2];
            int nx = 1, ny = 4;
            for(int i = 3 * k + 1; i <= n; ++i) {
                mp[nx][ny] = i;
                if(ny % 2 == 0) {
                    if(nx == x) {
                        ++ny;
                    } else {
                        ++nx;
                    }
                } else {
                    if(nx == 1) {
                        ++ny;
                    } else {
                        --nx;
                    }
                }
            }
        } else {
            int nx = 1, ny = 1;
            for(int i = 1; i <= n; ++i) {
                mp[nx][ny] = i;
                if(ny % 2 == 1) {
                    if(nx == x) {
                        ++ny;
                    } else {
                        ++nx;
                    }
                } else {
                    if(nx == 1) {
                        ++ny;
                    } else {
                        --nx;
                    }
                }
            }
        }
        for(int i = 1; i <= x; ++i) {
            for(int j = 1; j <= y; ++j) {
                printf("%d%c", mp[i][j], j == y ? '\n' : ' ');
            }
        }
    }
    return 0;
}

1007 Just an Old Puzzle(HDU6620+华容道+逆序对)

思路

\(0\)变成\(16\)然后矩阵合并成一列求出逆序对,加上\(0\)的初始位置如果是偶数则可以构造,否则就不能构造。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 1000000 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int t;
int a[20];

int main() {
    scanf("%d", &t);
    while(t--) {
        int ans = 0;
        for(int i = 0; i < 16; ++i) {
            scanf("%d", &a[i]);
            if(a[i] == 0) ans += i / 4 + 1 + i % 4 + 1;
            if(a[i] == 0) a[i] = 16;
            for(int j = 0; j <= i; ++j) {
                if(a[j] > a[i]) ++ans;
            }
        }
        if(ans & 1) printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

1008 K-th Closest Distance(6621+主席树+二分)

题意

对于一个数组\(a\)查询\(q\)次,每次问区间\([L,R]\)中距离\(p\)是第\(k\)大的是多少(第\(i\)个数与\(p\)的距离为\(|a_i-p|\))。

思路

二分答案然后看\([p-ans,p+ans]\)内有没有\(k\)个数。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 1000000 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int t, n, q, l, r, p, k, cnt;
int a[maxn], root[maxn];

struct node {
    int l, r, sum;
}tree[maxn*40];

void update(int l, int r, int &x, int &y, int pos) {
    tree[++cnt] = tree[y], tree[cnt].sum++, x = cnt;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(mid >= pos) update(l, mid, tree[x].l, tree[y].l, pos);
    else update(mid + 1, r, tree[x].r, tree[y].r, pos);
}

int query(int l, int r, int x, int y, int L, int R) {
    if(l >= L && r <= R) return tree[y].sum - tree[x].sum;
    if(l == r) return 0;
    int mid = (l + r) >> 1;
    if(R <= mid) return query(l, mid, tree[x].l, tree[y].l, L, R);
    else if(L > mid) return query(mid + 1, r, tree[x].r, tree[y].r, L, R);
    else return query(l, mid, tree[x].l, tree[y].l, L, mid) + query(mid + 1, r, tree[x].r, tree[y].r, mid + 1, R);
}

int main() {
#ifndef ONLINE_JUDGE
FIN;
time_t s = clock();
#endif // ONLINE_JUDGE
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &q);
        int mx = 0;
        cnt = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            mx = max(mx, a[i]);
        }
        for(int i = 1; i <= n; ++i) {
            update(1, mx, root[i], root[i-1], a[i]);
        }
        int las = 0;
        while(q--) {
            scanf("%d%d%d%d", &l, &r, &p, &k);
            l = l ^ las, r = r ^ las, p = p ^ las, k = k ^ las;
            int ub = mx, lb = 0, mid, ans = mx;
            while(ub >= lb) {
                mid = (ub + lb) >> 1;
                if(query(1, mx, root[l-1], root[r], p - mid, p + mid) >= k) {
                    ans = mid;
                    ub = mid - 1;
                } else {
                    lb = mid + 1;
                }
            }
            las = ans;
            printf("%d\n", ans);
        }
    }
    return 0;
}

1010 Minimal Power of Prime(HDU6623+素数筛)

题意

给你\(n\),问你\(n\)的素因子中最小的次数是多少。

思路

我们首先把\(4000\)内的素数筛出来,如果\(n\)还有剩余那么可以发现除了\(p^4,p^3,p^2,(p_1p_2)^2\)外其他情况指数最小都是\(1\),对于这几种情况分别开方就行,最后与小于\(4000\)的素数的最小次数取\(min\)就行。

本题与HDU5447(题解)很像,想清楚就会发现其实很简单,根本就不用把\(n\)完全唯一分解出来。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 4000 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int t, tot;
LL n;
bool v[maxn];
int p[maxn];

void init() {
    for(int i = 2; i < maxn; ++i) {
        if(!v[i]) {
            p[tot++] = i;
        }
        for(int j = 0; j < tot && i * p[j] < maxn; ++j) {
            v[i*p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}

int main() {
    init();
    scanf("%d", &t);
    while(t--) {
        scanf("%lld", &n);
        int cnt = inf;
        int flag = 0;
        for(int i = 0; i < tot; ++i) {
            if(n % p[i] == 0) {
                int num = 0;
                while(n % p[i] == 0) {
                    ++num;
                    n /= p[i];
                }
                if(num == 1) {
                    flag = 1;
                }
                cnt = min(cnt, num);
            }
        }
        if(flag) {
            printf("1\n");
            continue;
        }
        if(n == 1) {
            printf("%d\n", cnt);
            continue;
        }
        LL tmp = pow(n, 0.25);
        if(tmp * tmp * tmp * tmp == n) {
            cnt = min(cnt, 4);
        } else {
            ++tmp;
            if(tmp * tmp * tmp * tmp == n) {
                cnt = min(cnt, 4);
            } else {
                tmp = pow(n, 0.5);
                if(tmp * tmp == n) {
                    cnt = min(cnt, 2);
                } else {
                    ++tmp;
                    if(tmp * tmp == n) {
                        cnt = min(cnt, 2);
                    } else {
                        tmp = pow(n, 1.0 / 3);
                        if(tmp * tmp * tmp == n) {
                            cnt = min(cnt, 3);
                        } else {
                            ++tmp;
                            if(tmp * tmp * tmp == n) {
                                cnt = min(cnt, 3);
                            } else {
                                cnt = min(cnt, 1);
                            }
                        }
                    }
                }
            }
        }
        printf("%d\n", cnt);
    }
    return 0;
}
posted @ 2019-08-01 10:10  Dillonh  阅读(348)  评论(2编辑  收藏  举报