zoukankan      html  css  js  c++  java
  • 记2018/5/5 qbxt 测试

           记2018/5/5 qbxt 测试

      竞赛时间: 2018 年 5 月 5 日 13:30-17:00

    T1  

    一、maze(1s,512MB):

    简单的迷宫问题:给定一个n*m的迷宫,.表示可以通过,#表示不能通过。每一步可以向上下左右的任意方向移动,问是否能够正好k步从s走到t

    输入格式:

      第一行n,m表示迷宫的大小

      接下来n行每行m个字符表示迷宫

      接下来一行五个数字 x1,y1,x2,y2,k 表示起点为(x1,y1) 终点为(x2,y2) 步数为k

    输出格式:

       如果可以正好k步从s走到t输出方案,L表示向左,R表示向右,U表示向上,D表示向下。如果不能输出-1

    样例:

      输入:

      3 3

      …

      .#.

      …

      1 1 3 3 4

      输出:

       RRDD

    数据范围:

       30%的数据满足n,m<=3 保证一定能到

       60%的数据满足 n,m,k<=100

       100%的数据满足 n,m<=1000 k<=1000000

    思路:广搜 or 深搜 + 剪枝

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int n,m,x1,x2,y1,y2,K;
    char c;
    int g[1005][1005],f[1005][1005];
    int q[20000000][3];
    int answer[20000000], dir[1005][1005];
    int main() {
        freopen("maze.in","r",stdin);
        freopen("maze.out","w",stdout);
        scanf("%d %d",&n,&m);
        for (int i = 1; i<=n; i++)
            for (int j = 1; j<=m; j++) {
                scanf(" %c",&c);
                if (c=='.') {
                    g[i][j] = 1;
                } else if (c=='#') {
                    g[i][j] = 0;
                }
                f[i][j] = -1;
            }
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&K);
        if (g[x1][y1] == 0) {
            printf("-1
    ");
            return 0;
        }
        f[x1][y1] = 0;
        q[1][1] = x1;
        q[1][2] = y1;
        for (int s = 1,t = 1; s<=t; s++) {
            int x = q[s][1], y=q[s][2];
            if (x-1>0 && g[x-1][y] == 1 &&f[x-1][y] == -1) {
                f[x-1][y] = f[x][y]+1;
                t++;
                q[t][1] = x-1;
                q[t][2] = y;
                dir[x-1][y] = 1;
            }
            if (x+1<=n && g[x+1][y] == 1 && f[x+1][y] ==-1) {
                f[x+1][y] = f[x][y] +1;
                t++;
                q[t][1] = x+1;
                q[t][2] = y;
                dir[x+1][y] = 2;
            }
            if (y-1>0 && g[x][y-1]==1 && f[x][y-1]  == -1) {
                f[x][y-1] = f[x][y]+1;
                t++;
                q[t][1] = x;
                q[t][2] = y-1;
                dir[x][y-1] = 3;
            }
            if (y+1<=m && g[x][y+1] == 1 &&f[x][y+1] == -1) {
                f[x][y+1] = f[x][y] +1;
                t++;
                q[t][1] = x;
                q[t][2] = y+1;
                dir[x][y+1] = 4;
            }
        }
        if (f[x2][y2] == -1 || (f[x2][y2]+K)%2 == 1 || f[x2][y2]>K) {
            printf("-1
    ");
        } else {
            int x3 = x2, y3 = y2;
            for (int i = 0; x2!=x1 ||y2!=y1; i++) {
                answer[f[x2][y2]] = dir[x2][y2];
                int tmp = dir[x2][y2];
                if (tmp == 1) x2++;
                else if (tmp == 2) x2--;
                else if (tmp==3) y2++;
                else y2--;
            }
            x2 = x3,y2=y3;
            for (int i =0; i<=f[x2][y2]; i++) {
                if (answer[i] == 1) printf("U");
                else if (answer[i] == 2) printf("D");
                else if (answer[i]==3) printf("L");
                else if (answer[i]==4) printf("R");
            }
            for (int i = f[x2][y2]+1; i<=K; i+=2) {
                if (x2+1<=n && g[x2+1][y2]==1) printf("DU");
                else if (x2-1>0 && g[x2-1][y2]==1) printf("UD" );
                else if (y2+1<=m && g[x2][y2+1] == 1) printf("RL");
                else
                    printf("LR");
            }
        }
        return 0;
    }
    标程

    T2

    二、tree(1s,512MB):

    对于一个无根树,他的任意一个联通子图称为他的一个子树。现给出一个无根树,每个节点上有一个权值。 一个子树的权值为这个子树上所有节点权值的xor和。比如子树包含有权值为(1,2,4)的节点,那么子树的权值为 1 xor 2 xor 4 = 7。给定一个无根树求所有子树的权值的和,由于这个数可能很大结果对10^9+7取余。

    输入格式:

      第一行一个整数n表示树的节点数目

      第二行n个整数表示每个节点的权值

      接下来n-1行每行两个树 a,b表示a到b有一条边 (输入保证一定是一个树)

    输出格式:

      一个数 表示所有子树权值的和对10^9+7取余的结果

    样例:

      输入

      3

      1 2 3

      1 2

    1 3

    输出:

    11

    样例解释:

       所有的子树有{1}, {2},{3},{1,2},{1,3},{1,2,3}

       子树的权值为1,    2,  3,   3,     2,    0

       答案为 1+2+3+3+2+0 = 11

    数据范围:

       30%的数据满足 n<=5

       60%的数据满足 n<=100

       100%的数据满足 n<=100000 树上节点的权值为正整数<=10000000000

       其中有40%的数据满足节点权值=0或者1 另有其他10%的数据满足节点权值为1

    思路:Xor可以拆城若干个二进制位 之间互不影响

      考虑一个二进制位:

          随便选一个点为根,f[i][0] 表示以 i 为根的子树 xor 和为 0 的子树个数,f[i][1] 表示以 i 为根的子树xor 和为 1 的子树

        f[i][0] = f[i][0]*(f[son[i]][0] + 1) + f[i][1]*f[son[i][1]]

        f[i][1] = f[i][1]*(f[son[i][0]] + 1) + f[i][0]*f[son[i][1]]

        最后 for 一遍所有的节点 统计答案

        f[fa[i][0]] = f[fa[i]][0]*(f[i][0] + 1) + f[fa[i][1]]*f[i][1]

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn = 300000;
    int fa[maxn],ne[maxn],h[maxn],poi[maxn],q[maxn],vis[maxn];
    long long f[maxn][3];
    int a[maxn];
    int n,tot,x,y;
    int main() {
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
        scanf("%d",&n);
        for (int i =1; i<=n; i++)
            scanf("%d",&a[i]);
        for (int i = 0; i<n-1; i++) {
            scanf("%d%d",&x,&y);
            tot++;
            ne[tot] = h[x];
            h[x] = tot;
            poi[tot]= y;
            tot++;
            ne[tot]= h[y];
            h[y] = tot;
            poi[tot]=x;
        }
        q[1] = 1;
        vis[1] = 1;
        for (int s = 1, t = 1; s<=t; s++) {
            int x = q[s];
            for (int j = h[x]; j; j=ne[j])
                if (vis[poi[j]] == 0) {
                    fa[poi[j]] = x;
                    t++;
                    q[t] = poi[j];
                    vis[poi[j]] = 1;
                }
        }
        long long ans = 0;
        for (int t = 31; t>=0; t--) {
            for (int i = 1; i<=n; i++) {
    
                if (a[i]&(1<<t)) f[i][0] = 0, f[i][1] = 1;
                else f[i][0] = 1, f[i][1] = 0;
            }
            for (int i = n; i>=1; i--) {
                int k = q[i];
                int tmp0 = f[fa[k]][0],tmp1 = f[fa[k]][1];
                f[fa[k]][0] = (tmp0*(f[k][0]+1) + tmp1*f[k][1])%1000000007;
                f[fa[k]][1] = (tmp0*f[k][1] + tmp1*(f[k][0]+1))%1000000007;
            }
            for (int i =1; i<=n; i++)
                ans = (ans + f[i][1]*(1LL<<t))%1000000007;
        }
        printf("%lld",ans);
        return 0;
    }
    标程

    T3

    三、number(1s,512MB)

    数字的变化一直是千奇百怪的,于是本题只研究数字的加法和乘法。给定一个数s,每次你能将s变为 s+a 或者 s*b。问最少用几步变为t,无解输出-1

    输入格式:

      四个数 s,t,a,b (s,t为非负整数,a,b为正整数)

    输出格式:

       一个数表示最少的步数

    样例:

       输入

         5 26 3 2

        输出

       3

    样例解释:

       S = 5

       S = S * B = 5*2 = 10

       S = S+A = 5+3 = 13

       S = S*B= 13*2 = 26 = T

       所以只要3步

       数据范围:

          30%的数目满足 s,t,a,b<=100

          60%的数据满足s,t,a,b<=1000000

          100%的数据满足 s,t,a,b<=1000000000000000000

    思路:S = 0, 就是将 T/a  b进制分解将所有的数字加起来

        枚举 x 表示 s 乘了 x 次 b  记结果为 res

        将 ( T-res) / a   b 进制分解,小于 x 位的数字加起来大于等于 x 位的转成十进制加。( T-res) 能够整除a

    #include <cstdio>
    #include <cstring>
    using namespace std;
    long long s,t,a,b;
    int main() {
        freopen("number.in","r",stdin);
        freopen("number.out","w",stdout);
        scanf("%lld %lld %lld %lld",&s,&t,&a,&b);
        if (b==1) {
            if ((t-s) %a == 0) printf("%lld
    ",(t-s)/a);
            else printf("-1
    ");
            return 0;
        }
        long long ans;
        if ((t-s) %a == 0)
            ans = (t-s)/a ;
        else ans = 1000000000000000003LL;
        for (int i = 1; ; i++) {
            if (t/s < b) break;
            s*=b;
            long long tt = t-s;
            if (tt%a == 0) {
                tt/=a;
                long long ans1 =0;
                for (int j = 1; j<=i; j++) {
                    ans1+=tt%b;
                    tt/=b;
                }
                ans1+=tt+i;
                if (ans1<ans) ans = ans1;
            }
        }
        if (ans != 1000000000000000003) printf("%lld",ans);
        else printf("-1
    ");
    }
    标程

    希望今天前往北京参加APIO的学长学姐以及同级的同学可以考出让自己满意的成绩

      不负初心,继续前进

  • 相关阅读:
    equals与”==”的区别
    数学--数论--积性函数(初步)
    数学--数论-多重集排列组合与母函数
    数学--数论--POJ 1061青蛙的约会 (扩展欧几里得算法)
    数学--数论--POJ281(线性同余方程)
    数学--数论--HDU1222 狼和兔子(最大公约数)
    数学--数论--HDU1576 A / B(逆元)
    VScode像Codeblocks一样,不启动调试和Debug直接运行
    数学--数论--鸽巢原理
    图论--拓扑排序--模板
  • 原文地址:https://www.cnblogs.com/v-vip/p/8996235.html
Copyright © 2011-2022 走看看