记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\n");
        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\n");
    } 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\n",(t-s)/a);
        else printf("-1\n");
        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\n");
}
标程

 

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

  不负初心,继续前进

posted @ 2018-05-05 21:30  落云小师妹  阅读(344)  评论(0编辑  收藏  举报