• 省选模拟赛 LYK loves rabbits(rabbits)


    题目描述

    LYK喜欢兔子,它在家中养了3只兔子。

    有一天,兔子不堪寂寞玩起了游戏,3只兔子排成一排,分别站在a,b,c3个位置。

    游戏的规则是这样的,重复以下步骤k次:选择两个不同的兔子AB,假如它们位于XYA可以从X跳到Y+Y-X处,但是跳跃时是不允许一下子跳过两只兔子的,也就是说第三只兔子不在[min{X,Y+Y-X},max{X,Y+Y-X}]处。

    现在3只小兔子的位置分别到了x,y,z(3只兔子长得一样,即三只兔子跳完之后的顺序可以变化)处,但是它们忘记一开始是怎么跳的了,想让你帮它们还原跳法。但这个问题非常easy,于是LYK要求你输出方案总数。

    保证答案有解。

    由于答案巨大,你只需输出答案对1e9+7取模后的结果就可以了。

    输入格式(rabbits.in)

    第一行3个数a,b,c

    第二行3个数x,y,z

    第三行一个数k

    数据保证3只兔子的起始位置a,b,c严格递增且3只兔子最终的位置x,y,z严格递增。

    输出格式(rabbits.out)

    一行表示方案总数。

    输入样例1

    0 2 5

    0 2 5

    2

    输出样例1

    3

    输入样例2

    0 2 4

    0 2 4

    2

    输出样例2

    2

    样例解释

    对于样例1:共有3种跳法,第一次跳完后的位置分别是{0,-2,5},{4,2,5},{0,8,5}

    数据范围

    对于100%的数据k<=100,|a|,|b|,|c||x|,|y|,|z|<=10^18

    分析:非常神奇的一道题.

       将3只兔子所在的位置看成一个状态. 那么起点状态S(a,b,c),终点状态T(x,y,z).  

       如果中间的兔子往两边跳,那么它能转移到2个新的状态. 如果外面的兔子想往里面跳,那么最多只能有一个兔子往里跳. 这些状态其实构成了一棵二叉树:如果中间的兔子往两边跳,那么就转移到2个儿子节点中,如果两边的兔子往里面跳,就转移到父亲节点中.

       那么现在的问题就变成了:在一棵二叉树中,求节点S到节点T恰好经过k条边的方案数.

       两个点的路径只与它们到LCA之间的路径有关. 令f(i,j,k)表示S与LCA(S,T)之间的距离为i,T与LCA(S,T)之间的距离为j,还能走k条边的方案数. 固定T,只考虑S的移动,分以下几种情况讨论:

       1.如果S已经是LCA了. 如果T也是LCA了. S可以往上走也可以往两个儿子节点走. f(i,j,k) += f(i + 1,j,k - 1) * 2 + f(i,j - 1,k - 1). 乘2是因为有2个儿子节点可以走.  如果T不是LCA. 那么可以走到父亲节点,走到不是T的那个子树和走到T所在的那个子树上. f(i,j,k) += f(i,j + 1,k - 1) + f(i,j - 1,k - 1) + f(i + 1,j,k - 1).

       2.如果S不是LCA. S既可以走到2个儿子节点,也可以走到父亲节点. 转移和上面的类似.

       知道了如何求方案数,该怎么建树呢?

       首先需要明确的是:我们不需要建出整棵树. 因为树的结构就是一棵完全二叉树,每一棵子树的形态结构都是一样的. 根据dp需要的信息,我们只需要求出S和T距离LCA的深度即可.

       先要求出LCA. LCA处的两个状态的兔子的位置全都相同. 让S状态的外面的兔子不断往里跳,T状态的也如此. 最后肯定会有两个状态的兔子的位置完全相等,最早出现的这个状态就是LCA.  为什么要往里跳呢?因为只有这样才能枚举出优先的状态. 否则二叉树就会无限向下扩展.

       小结一下. 做这道题首先要想到把3个兔子的位置看作一个状态. 状态有3种不同的转移方式. 其中有2种的本质是相同的. 联想到二叉树. 求状态A到B的方案数实际上就是求路径数. 树上路径只和这两个点以及它们的LCA有关,由此可以设计出状态. 最后求LCA运用中间相遇法. 思路还是挺巧妙的.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const int maxn = 1010,mod = 1e9+7;
    ll a[maxn],b[maxn],c[maxn],x[maxn],y[maxn],z[maxn],k,k1,k2,pos1,pos2,f[110][110][110];
    bool flag = false;
    
    ll dfs(ll X,ll Y,ll K)
    {
        if (!X && !Y && !K)
            return 1;
        if (X + Y > K)
            return 0;
        if (!X && Y > k2)
            return 0;
        if (f[X][Y][K] != -1)
            return f[X][Y][K];
        if (!X)
        {
            if (!Y)
                f[X][Y][K] = (dfs(X,Y + 1,K - 1) + dfs(X + 1,Y,K - 1) * 2 % mod) % mod;
            else
                f[X][Y][K] = ((dfs(X,Y + 1,K - 1) + dfs(X,Y - 1,K - 1)) % mod + dfs(X + 1,Y,K - 1)) % mod;
        }
        else
            f[X][Y][K] = (dfs(X + 1,Y,K - 1) * 2 % mod + dfs(X - 1,Y,K - 1)) % mod;
        return f[X][Y][K];
    }
    
    int main()
    {
        memset(f,-1,sizeof(f));
        scanf("%lld%lld%lld%lld%lld%lld%lld",&a[0],&b[0],&c[0],&x[0],&y[0],&z[0],&k);
        while (k1 <= k)
        {
            if (b[k1] - a[k1] == c[k1] - b[k1])
                break;
            if (b[k1] - a[k1] < c[k1] - b[k1])
            {
                k1++;
                a[k1] = b[k1 - 1];
                b[k1] = 2 * b[k1 - 1] - a[k1 - 1];
                c[k1] = c[k1 - 1];
            }
            else
            {
                k1++;
                a[k1] = a[k1 - 1];
                c[k1] = b[k1 - 1];
                b[k1] = 2 * b[k1 - 1] - c[k1 - 1];
            }
        }
        while (k2 <= k)
        {
            if (y[k2] - x[k2] == z[k2] - y[k2])
                break;
            if (y[k2] - x[k2] < z[k2] - y[k2])
            {
                k2++;
                x[k2] = y[k2 - 1];
                y[k2] = 2 * y[k2 - 1] - x[k2 - 1];
                z[k2] = z[k2 - 1];
            }
            else
            {
                k2++;
                x[k2] = x[k2 - 1];
                z[k2] = y[k2 - 1];
                y[k2] = 2 * y[k2 - 1] - z[k2 - 1];
            }
        }
        for (pos1 = 0; pos1 <= k1 && !flag; pos1++)
            for (pos2 = 0; pos2 <= k2 && !flag; pos2++)
                if (a[pos1] == x[pos2] && b[pos1] == y[pos2] && c[pos1] == z[pos2])
                    flag = true;
        pos1--;
        pos2--;
        printf("%lld
    ",dfs(pos1,pos2,k) % mod);
    
        return 0;
    }
  • 相关阅读:
    mysql对字段分割内容查询
    vue相关报错
    java多线程面试题
    java的消息队列
    电子商务大数据平台实训系统业务数据仓库总结
    电子商务大数据平台实训用户行为数仓业务总结
    电子商务大数据平台实训第一阶段总结
    Java 并发基础常见面试题总结
    window 平台 安装MongoDB
    java知识汇总(第六天)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8647862.html
Copyright © 2020-2023  润新知