zoukankan      html  css  js  c++  java
  • Codeforces 980 并查集/模拟贪心最小字典序 找规律/数去除完全平方因子 逆思维倍增预处理祖先标记点

    A

    /*Huyyt*/
    #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const ll LLmaxn = 2e18;
    int main()
    {
            string a;
            cin >> a;
            int b=0, c=0;
            for (int i = 0; i < a.size(); i++)
            {
                    if (a[i] == '-')
                    {
                            b++;
                    }
                    else
                    {
                            c++;
                    }
            }
            //cout<<b<<" "<<c<<endl;
            if (c == 0)
            {
                    cout << "YES" << endl;
                    return 0;
            }
            if (b % c != 0)
            {
                    cout << "NO" << endl;
            }
            else
            {
                    cout << "YES" << endl;
            }
            return 0;
    }
    View Code

    B

    解:

    注意只要是上下对称或者是左右对称就可以使得 1-4 有一条路径的话 2-3 也有相对应的一条路径

    剩下的就容易构造了

    /*Huyyt*/
    #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const ll LLmaxn = 2e18;
    char ans[5][105];
    int main()
    {
            int n, k;
            cin >> n >> k;
            for (int i = 1; i <= 4; i++)
            {
                    for (int j = 1; j <= n; j++)
                    {
                            ans[i][j] = '.';
                    }
            }
            int sum = (n - 2) * 2;
            if (k > sum)
            {
                    cout << "NO" << endl;
                    return 0;
            }
            cout << "YES" << endl;
            if (k % 2 == 0)
            {
                    int cur = k;
                    for (int j = 2; j <= n - 1 && cur; j++)
                    {
                            for (int i = 2; i <= 3 && cur; i++)
                            {
                                    ans[i][j] = '#';
                                    cur--;
                            }
                    }
            }
            else
            {
                    k--;
                    ans[2][n / 2 + 1] = '#';
                    for (int i = 2; i <= 3 && k; i++)
                    {
                            for (int j = 2; j <= n / 2 && k; j++)
                            {
                                    ans[i][j] = ans[i][n - j + 1] = '#';
                                    k -= 2;
                            }
                    }
            }
            for (int i = 1; i <= 4; i++)
            {
                    for (int j = 1; j <= n; j++)
                    {
                            cout << ans[i][j];
                    }
                    cout << endl;
            }
            return 0;
    }
    View Code

    C

    解:

    可以用并查集维护每个点最小到达的地方 也因为N<=1E5,K<=256 直接暴力模拟也可以

    /*Huyyt*/
    #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const ll LLmaxn = 2e18;
    char ans[5][105];
    int main()
    {
            int n, k;
            cin >> n >> k;
            for (int i = 1; i <= 4; i++)
            {
                    for (int j = 1; j <= n; j++)
                    {
                            ans[i][j] = '.';
                    }
            }
            int sum = (n - 2) * 2;
            if (k > sum)
            {
                    cout << "NO" << endl;
                    return 0;
            }
            cout << "YES" << endl;
            if (k % 2 == 0)
            {
                    int cur = k;
                    for (int j = 2; j <= n - 1 && cur; j++)
                    {
                            for (int i = 2; i <= 3 && cur; i++)
                            {
                                    ans[i][j] = '#';
                                    cur--;
                            }
                    }
            }
            else
            {
                    k--;
                    ans[2][n / 2 + 1] = '#';
                    for (int i = 2; i <= 3 && k; i++)
                    {
                            for (int j = 2; j <= n / 2 && k; j++)
                            {
                                    ans[i][j] = ans[i][n - j + 1] = '#';
                                    k -= 2;
                            }
                    }
            }
            for (int i = 1; i <= 4; i++)
            {
                    for (int j = 1; j <= n; j++)
                    {
                            cout << ans[i][j];
                    }
                    cout << endl;
            }
            return 0;
    }
    View Code

    D

    卡题意...

    给出一个数组,把里面的数字分组,使得每一个组里面的数两两相乘都是完全平方数.

    问最少可以分成的组数k是多少.

    现在一个人有一个数组,他想知道这个数组的连续子数组中,使得上面的问题答案分别为1到n的数组有多少个.

    第一种做法:

    注意当一个数X的因数有完全平方数Y的时候 把这个数替换为X/Y并不影响结果

    当一个数是0的时候要特判 要因为0乘任何数都是0可以加入任意一组

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <set>
    #include <math.h>
    using namespace std;
    const int N = 500100;
    int a[N];
    int b[N];
    int c[N];
    bool vis[N];
    int mabs(int x)
    {
        return x >= 0 ? x : -x;
    }
    int main()
    {
        int n;
        int cnt = 0;
        scanf("%d",&n);
        for (int i = 0;i < n;i++)
        {
            scanf("%d",&a[i]);
            if (a[i] != 0) cnt++;
        }
        if (cnt == 0)
        {
            printf("%d ",n * (n + 1) / 2);
            for (int i = 1;i < n;i++) printf("0 ");
        }
        else
        {
            for (int i = 0;i < n;i++)
            {
                if (a[i] == 0) continue;
                int tmp = mabs(a[i]);
                for (int j = 2;j * j <= tmp;j++)
                {
                    int t = j * j;
                    while (a[i] % t == 0)
                    {
                        a[i] /= t;
                    }
                    //if (a[i] < t) break;加了这个就wa,卡了一晚上,考虑的应该是绝对值的情况
                }
            }
            for (int i = 0;i < n;i++) c[i] = a[i];
            sort(c,c+n);
            int js = unique(c,c+n) - c;
            for (int i = 0;i < n;i++)
            {
                if (a[i] == 0) continue;
                int p = lower_bound(c,c+js,a[i]) - c + 1;
                a[i] = p;
            }
            for (int i = 0;i < n;i++)
            {
                memset(vis,0,sizeof(vis));
                int num = 0;
                for (int j = i;j < n;j++)
                {
                    if (!vis[a[j]] && a[j] != 0)
                    {
                        num++;
                        vis[a[j]] = 1;
                    }
                    int tt = max(num,1);
                    b[tt]++;
                }
            }
            for (int i = 1;i <= n;i++)
            {
                printf("%d ",b[i]);
            }
        }
        return 0;
    }
    View Code

    第二种做法:

    可以证明当A*B为完全平方数B*C也为完全平方数时 A*C也是完全平方数

    所以只要N^2遍历 用并查集维护每个数属于哪个集合就行 注意0可以属于任意一个集合

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 5001;
    long long a[N];
    int ans[N], fa[N], d[N];
    int bz[N];
    int n, sum, tot;
    bool check(long long x)
    {
            if (x < 0)
            {
                    return 0;
            }
            long long y = sqrt(x);
            return y * y == x || (y - 1) * (y - 1) == x || (y + 1) * (y + 1) == x;
    }
    int main()
    {
            ios::sync_with_stdio(false);
            cin >> n;
            for (int i = 1; i <= n; i++)
            {
                    fa[i] = i;
            }
            for (int i = 1; i <= n; i++)
            {
                    cin >> a[i];
                    if (a[i])
                    {
                            for (int j = 1; j <= d[0]; j++)
                                    if (check(a[i]*a[d[j]]))
                                    {
                                            fa[i] = d[j];
                                            break;
                                    }
                            if (fa[i] == i)
                            {
                                    d[++d[0]] = i;
                            }
                    }
            }
            for (int i = 1; i <= n; i++)
            {
                    sum = 0;
                    tot++;
                    for (int j = i; j <= n; j++)
                    {
                            if (a[j] && bz[fa[j]] != tot)
                            {
                                    bz[fa[j]] = tot, sum++;
                            }
                            ans[max(sum, 1)]++;
                    }
            }
            for (int i = 1; i <= n; i++)
            {
                    cout << ans[i] << ' ';
            }
            return 0;
    }
    View Code

     E

    给你N个点 组成的一颗树 分别从1标号到N 每个点的粉丝数量为2^i个

    要求是选择K个点删除 使得剩下没被删的点保持连通且剩下的粉丝数量最大

    一旦某个点被删除则其不能通过且该点的粉丝数量清零

    假如做法顺着做 找出需要删除那些点的话 因为要保证连通性所以删除一个点需要删除掉他所有子树的点 不好做

    题目提示你K<N 所以点N是一定可以保留的 就以N为根倍增预处理祖先 倒着做 找出不需要删除的点即可

    /* Huyyt */
    #include <bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define mkp(a,b) make_pair(a,b)
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const long long mod = 1e9 + 7;
    const int N = 1e6 + 5;
    inline int readint()
    {
            char c = getchar();
            int ans = 0;
            while (c < '0' || c > '9')
            {
                    c = getchar();
            }
            while (c >= '0' && c <= '9')
            {
                    ans = ans * 10 + c - '0', c = getchar();
            }
            return ans;
    }
    vector<int> tree[N];
    bool check[N];
    int father[N][21];
    int deep[N];
    void dfs(int x, int level)
    {
            for (int i = 0; father[father[x][i]][i]; i++)
            {
                    father[x][i + 1] = father[father[x][i]][i];
            }
            deep[x] = level;
            for (int i = 0; i < tree[x].size(); i++)
            {
                    int to = tree[x][i];
                    if (to == father[x][0])
                    {
                            continue;
                    }
                    father[to][0] = x;
                    dfs(to, level + 1);
            }
    }
    int main()
    {
            int n, k;
            n = readint(), k = readint();
            //cout << n << " " << k << endl;
            int u, v;
            for (int i = 1; i < n; i++)
            {
                    u = readint(),v = readint();
                    tree[u].pb(v);
                    tree[v].pb(u);
            }
            k = n - k;
            k--, check[n] = 1;
            dfs(n, 1);
            for (int i = n - 1; i >= 1 && k; i--)
            {
                    int aim = -1;
                    int now = i;
                    if (check[i])
                    {
                            continue;
                    }
                    for (int j = 20; j >= 0; j--)
                    {
                            if (father[now][j] == 0 || check[father[now][j]])
                            {
                                    continue;
                            }
                            now = father[now][j];
                    }
                    if (deep[i] - deep[now] + 1 <= k)
                    {
                            now = i;
                            while (now != 0 && !check[now])
                            {
                                    check[now] = 1;
                                    k--;
                                    now = father[now][0];
                            }
                    }
            }
            for (int i = 1; i <= n - 1; i++)
            {
                    if (!check[i])
                    {
                            cout << i << " ";
                    }
            }
            return 0;
    }
    View Code
  • 相关阅读:
    C++容器不要类型转换
    栈区、堆区、全局区、文字常量区、程序代码区
    C++数据类型字节数
    Exception-Safe Generic Containers
    饭碗是要靠抢的
    Wireshark抓包实例分析TCP重复ACK与乱序
    OSPF
    孩子,我该让你更好的长大!
    云,除了卖,我们还剩下什么?
    动态路由3--链路状态路由选择协议
  • 原文地址:https://www.cnblogs.com/Aragaki/p/9016076.html
Copyright © 2011-2022 走看看