zoukankan      html  css  js  c++  java
  • 2018年第十届ACMICPC四川省大学程序设计竞赛

    ..拿金了 没给学校丢脸

    A

    ....SB题啊 比赛的时候都没看 裸的一个bitset前缀和

    先开一个1e4*1e4的二维bitset数组 初始第i个数组的值为1 << i (即B[i]=1 B[i]<<=i)

    很容易我们可以知道要单独翻转某一位而不去影响其他位的话 方法是唯一的

    然后我们从可以后往前DP 就可以知道要单独翻转某一位的话需要翻转那些位

    最后的每次翻转过后的答案就是   上一个答案^PreL-1 ^PreR

    注意用cout的话容易System Error......(再喷一次OJ

    /*Huyyt*/
    #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
    const int mod = 1e9 + 7, gakki = 5 + 2 + 1 + 19880611 + 1e9;
    const int MAXN = 1e5 + 5, MAXM = 1e5 + 5, N = 1e4 + 5;
    const int MAXQ = 100010;
    int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1;
    inline void addedge(int u, int v)
    {
            to[++tot] = v;
            nxt[tot] = Head[u];
            Head[u] = tot;
    }
    inline void read(int &v)
    {
            v = 0;
            char c = 0;
            int p = 1;
            while (c < '0' || c > '9')
            {
                    if (c == '-')
                    {
                            p = -1;
                    }
                    c = getchar();
            }
            while (c >= '0' && c <= '9')
            {
                    v = (v << 3) + (v << 1) + c - '0';
                    c = getchar();
            }
            v *= p;
    }
    int n, m, l, r;
    bitset<N> B[10005], pre[10005], ans;
    int main()
    {
            ios_base::sync_with_stdio(0);
            cin.tie(0);
            int T;
            read(T);
            while (T--)
            {
                    ans.reset();
                    read(n), read(m);
                    for (int i = 1; i <= n; i++)
                    {
                            B[i].reset();
                    }
                    B[0] = 1;
                    for (int i = n; i >= 1; i--)
                    {
                            B[i] = 1;
                            B[i] <<= i;
                            for (int j = 2 * i; j <= n; j += i)
                            {
                                    B[i] = B[i] ^ B[j];
                            }
                    }
                    pre[0] = 0;
                    for (int i = 1; i <= n; i++)
                    {
                            pre[i] = pre[i - 1] ^ B[i];
                    }
                    for (int i = 1; i <= m; i++)
                    {
                            read(l), read(r);
                            ans = ans ^ pre[l - 1] ^ pre[r];
                            printf("%d
    ", ans.count());
                    }
            }
            return 0;
    }
    View Code

    B(比赛通过)

    水题

    C(比赛通过)

    把不同的字符串看作是点

    用AC自动机建边 跑一遍即可

    D

    最后没有时间了 没做出来 其实蛮简单的

    在没有确定根之前 满足一对pilot要求的点是这两个点的子树

    在确定了一个节点为根之后 就可以分为两种情况

    1.两个pilot不是一条链上的 则两个点的子树+1

    2.两个pilot是一条链上的 则先全部节点+1 再把父亲到这个儿子的子树(不包括父亲节点)-1 再把儿子的子树+1

    最后看值为m的点有多少个 即为答案+1 -1的这些操作用一个数组维护 dfs从父亲到儿子作前缀和即可

    可以倍增(NlogN)做 也可以tarjan+dfs序(N)

    倍增:

    加读入挂的话 可以减到5500ms

    /*Huyyt*/
    #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
    const int mod = 1e9 + 7, gakki = 5 + 2 + 1 + 19880611 + 1e9;
    const int MAXN = 1e5 + 5, MAXM = 1e5 + 5;
    const int maxl = 25;
    const int MAXQ = 100010;
    int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1;
    inline void addedge(int u, int v)
    {
            to[++tot] = v;
            nxt[tot] = Head[u];
            Head[u] = tot;
    }
    int flag = 0;
    int n, m, anser = 0;
    int presum[MAXN];
    int grand[MAXN][maxl];  //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离
    int gw[MAXN][maxl];   //维护距离的数组
    int depth[MAXN];//深度
    int root;
    int N; //N的意思是最多能跳几层
    void dfs(int x)//dfs建图
    {
            for (int i = 1; i <= N; i++) //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组
            {
                    grand[x][i] = grand[grand[x][i - 1]][i - 1];  //倍增 2^i=2^(i-1)+2^(i-1)
            }
            for (int i = Head[x]; i; i = nxt[i])
            {
                    int v = to[i];
                    if (v != grand[x][0])
                    {
                            depth[v] = depth[x] + 1;
                            grand[v][0] = x;
                            dfs(v);
                    }
            }
    }
    void Init()
    {
            tot = 1;
            anser = 0;
            for (int i = 1; i <= n; i++)
            {
                    presum[i] = Head[i] = 0;
            }
            N = floor(log(n + 0.0) / log(2.0));//最多能跳的2^i祖先
            depth[root] = 0; //根结点的祖先不存在,用-1表示
            depth[0] = -1;
            memset(grand, 0, sizeof(grand));
    }
    int lca(int a, int b)
    {
            if (depth[a] > depth[b])
            {
                    swap(a, b);        //保证a在b上面,便于计算
            }
            int ans = 0;
            for (int i = N; i >= 0; i--) //类似于二进制拆分,从大到小尝试
            {
                    if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) //a在b下面且b向上跳后不会到a上面
                    {
                            b = grand[b][i];        //先把深度较大的b往上跳
                    }
            }
            if (a == b)
            {
                    return a;
            }
            for (int j = N; j >= 0; j--) //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。
            {
                    if (grand[a][j] != grand[b][j])
                    {
                            a = grand[a][j];
                            b = grand[b][j];
                    }
            }
            return grand[a][0];
    }
    int lca2(int a, int b)
    {
            if (depth[a] > depth[b])
            {
                    swap(a, b);        //保证a在b上面,便于计算
            }
            int ans = 0;
            for (int i = N; i >= 0; i--) //类似于二进制拆分,从大到小尝试
            {
                    if (depth[a] + 1 < depth[b] && depth[grand[b][i]] >= depth[a] + 1) //a在b下面且b向上跳后不会到a上面
                    {
                            b = grand[b][i];        //先把深度较大的b往上跳
                    }
            }
            return b;
    }
    void getadd(int x, int fa)
    {
            presum[x] += presum[fa];
            for (int i = Head[x]; i; i = nxt[i])
            {
                    int v = to[i];
                    if (v != fa)
                    {
                            getadd(v, x);
                    }
            }
    }
    int main()
    {
            ios_base::sync_with_stdio(0);
            cin.tie(0);
            root = 1;
            int T;
            scanf("%d",&T);
            while (T--)
            {
                    int u, v;
                    scanf("%d %d", &n, &m);
                    Init();
                    for (int i = 1; i <= n - 1; i++)
                    {
                            scanf("%d %d", &u, &v);
                            addedge(u, v), addedge(v, u);
                    }
                    dfs(root);
                    for (int i = 1; i <= m; i++)
                    {
                            scanf("%d %d", &u, &v);
                            int now = lca(u, v);
                            //cout << "lca" << now << endl;
                            if (now == u || now == v)
                            {
                                    int cnt = lca2(u, v);
                                    //cout << "lca2 " << cnt << endl;
                                    if (now == u)
                                    {
                                            presum[1]++;
                                            presum[cnt]--;
                                            presum[v]++;
                                    }
                                    else
                                    {
                                            presum[1]++;
                                            presum[cnt]--;
                                            presum[u]++;
                                    }
                            }
                            else
                            {
                                    presum[u]++, presum[v]++;
                            }
                    }
                    getadd(1, 0);
    //                for (int i = 1; i <= n; i++)
    //                {
    //                        cout << "presum" << i << " " << presum[i] << endl;
    //                }
                    for (int i = 1; i <= n; i++)
                    {
                            if (presum[i] == m)
                            {
                                    //cout << i << endl;
                                    anser++;
                            }
                    }
                    cout<<anser<<endl;
            }
            return 0;
    }
    View Code

    tarjan做法:

    没有用到dfs序 只是dfs的时候记录了一下当前节点的儿子节点QQQnxt[u]=v

    极限可以做到2500ms

    更新:莫名其妙他们的OJ变快(正常)了 跑了340ms 上面的倍增则跑了1000ms

    /*Huyyt*/
    #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
    const int mod = 1e9 + 7, gakki = 5 + 2 + 1 + 19880611 + 1e9;
    const int MAXN = 1e5 + 5, MAXM = 1e5 + 5, N = 1e5 + 5;
    const int MAXQ = 100010;
    int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1;
    inline void addedge(int u, int v)
    {
            to[++tot] = v;
            nxt[tot] = Head[u];
            Head[u] = tot;
    }
    inline void read(int &v)
    {
            v = 0;
            char c = 0;
            int p = 1;
            while (c < '0' || c > '9')
            {
                    if (c == '-')
                    {
                            p = -1;
                    }
                    c = getchar();
            }
            while (c >= '0' && c <= '9')
            {
                    v = (v << 3) + (v << 1) + c - '0';
                    c = getchar();
            }
            v *= p;
    }
    int QQQnxt[MAXN];
    int QQQanser[MAXN];
    pair<int, int> QQQ[MAXM];
    int n, m, anser = 0;
    int presum[MAXN], ans[MAXN];
    bool vis[MAXN];//访问标记
    int ancestor[MAXN];//祖先
    struct Query
    {
            int q, next;
            int index;//查询编号
    } query[MAXQ * 2];
    int tt, Q, h[MAXQ], answer[MAXQ];
    int F[MAXN];//需要初始化为-1
    int find(int x)
    {
            if (F[x] == -1)
            {
                    return x;
            }
            return F[x] = find(F[x]);
    }
    void bing(int u, int v)
    {
            int t1 = find(u);
            int t2 = find(v);
            if (t1 != t2)
            {
                    F[t1] = t2;
            }
    }
    inline void add_query(int u, int v, int index)
    {
            query[tt].q = v;
            query[tt].next = h[u];
            query[tt].index = index;
            h[u] = tt++;
            query[tt].q = u;
            query[tt].next = h[v];
            query[tt].index = index;
            h[v] = tt++;
    }
    void LCA(int u)
    {
            ancestor[u] = u;
            vis[u] = true;
            for (int i = Head[u]; i; i = nxt[i])
            {
                    int v = to[i];
                    QQQnxt[u] = v;
                    if (vis[v])
                    {
                            continue;
                    }
                    LCA(v);
                    bing(u, v);
                    ancestor[find(u)] = u;
            }
            for (int i = h[u]; i != -1; i = query[i].next)
            {
                    int v = query[i].q;
                    if (vis[v])
                    {
                            answer[query[i].index] = ancestor[find(v)];
                            if (answer[query[i].index] == v)
                            {
                                    QQQanser[query[i].index] = QQQnxt[v];
                            }
                    }
            }
    }
    void init()
    {
            tt = tot = 1;
            anser = 0;
            for (int i = 1; i <= n; i++)
            {
                    ancestor[i] = presum[i] = Head[i] = 0;
                    vis[i] = F[i] = h[i] = -1;
            }
    }
    void getadd(int x, int fa)
    {
            presum[x] += presum[fa];
            for (int i = Head[x]; i; i = nxt[i])
            {
                    int v = to[i];
                    if (v != fa)
                    {
                            getadd(v, x);
                    }
            }
    }
    int main()
    {
            ios_base::sync_with_stdio(0);
            cin.tie(0);
            int T;
            read(T);
            while (T--)
            {
                    int u, v;
                    read(n), read(m);
                    init();
                    for (int i = 1; i <= n - 1; i++)
                    {
                            read(u), read(v);
                            addedge(u, v), addedge(v, u);
                    }
                    for (int i = 0; i < m; i++)
                    {
                            read(u), read(v);
                            add_query(u, v, i);
                            QQQ[i] = make_pair(u, v);
                    }
                    LCA(1);
                    for (int i = 0; i < m; i++)
                    {
                            //cout << answer[i] << endl;
                            if (answer[i] == QQQ[i].first)
                            {
                                    //cout<<QQQanser[i]<<endl;
                                    presum[1]++;
                                    presum[QQQanser[i]]--;
                                    presum[QQQ[i].second]++;
                            }
                            else if (answer[i] == QQQ[i].second)
                            {
                                    //cout<<QQQanser[i]<<endl;
                                    presum[1]++;
                                    presum[QQQanser[i]]--;
                                    presum[QQQ[i].first]++;
                            }
                            else
                            {
                                    presum[QQQ[i].first]++;
                                    presum[QQQ[i].second]++;
                            }
                    }
                    getadd(1, 0);
                    //                for (int i = 1; i <= n; i++)
                    //                {
                    //                        cout << "presum" << i << " " << presum[i] << endl;
                    //                        cout << "ans" << i << " " << ans[i] << endl;
                    //                }
                    for (int i = 1; i <= n; i++)
                    {
                            if (presum[i] == m)
                            {
                                    //cout << i << endl;
                                    anser++;
                            }
                    }
                    printf("%d
    ", anser);
            }
            return 0;
    }
    View Code

    E(比赛通过)

    注意年=月=日的特殊合法情况即可

    F(比赛通过)

    如果知道中位数的话 我们就可以n2logn暴力地知道答案 剩下就是怎么找中位数的问题

    找中位数可以用权值线段树来做 注意单个点权值占一半以上的情况

    总复杂度3*T*n2logn/2

    G

    无视

    H(比赛通过)

    水题

    I(比赛通过)

    树分治中点分治的一个小部分 变成带权的了 直接dfs一次即可

    J(比赛通过)

    结论题

    很容易可以知道前三个我们肯定是可以确认是原数列的前三个

    因为A0=0   A0+A1   A0+A2这三个肯定是最小的

    比如样例0 1 2 2 我们可以先确认前三个0 1 2

    则这三个产生的数列是1 2 3 接下来我们看与目标数列1 2 2 3 3 4对比最小的缺什么

    很容易发现缺了个2 所以我们必须补个2

    因为数列是非递减的Ai与之前数相加产生的数不大于Ai+1与之前数相加所产生的数

    这样继续check直到数列被填满

    写的话就是直接暴力找 看起来复杂度会爆炸 但其实中间很多就直接break相当于剪枝了 能过

    K

    题意:

    你要玩一个猜数游戏 答案为X 你最多只能问N次 问的时间最多不能超过V

    第i次询问你可以选一个数Y猜 如果Y大于X的话 会花费Ai的时间 不然的话会花费Ai+Bi的时间

    你只有每次猜完后才可以猜下一次 问你最后可以从1开始猜到的最大区间长度为多少

    解:

    dp dp[i][j]表示只使用询问 i到n 而且时间不超过j所能知道的答案

    dp[i][j] = dp[i+1][j-Ai] + dp[i+1][j-Ai-Bi]  但是边界的时候需要考虑一些细节... 
  • 相关阅读:
    Java学习笔记(一)语法
    【转,整理】C# 非托管代码
    HTML5学习笔记(七)WebSocket
    HTML5学习笔记(七)HTML5 服务器发送事件(Server-Sent Events)
    MySQL修改表格内容3
    MySQL修改表格内容2
    MySQL修改表格内容
    MySQL创建表格
    if-else if-else;多选择结构
    面向对象和面向过程的初步概念
  • 原文地址:https://www.cnblogs.com/Aragaki/p/9142250.html
Copyright © 2011-2022 走看看