2017百度之星程序设计大赛 - 复赛 题解(1,3)

写在前面

我的第三篇博客:补8月18日的百度之星复赛。
抱着拿衣服的目的而来,不能否认心中也是有着进决赛的念想的。
只AC了一道1001,其他各种没思路,不得不说基本功一点都不扎实。

1001 Arithmetic of Bomb (HDU 6144) (模拟)

给出数据组数t(100)和t个Bomb Expression(最长1000)
关于Bomb Expression的解释,可以参见我的BNF学习笔记中的例子。
大意为将若干个(a)#(b)的形式分别展开成aaaa……a(b个a),然后对1e9+7取模。
其中b为一位非0数字。

逐位取模即可,碰到a保存下来,读入b之后,重复b个a的取模。

#include 
#include 
#define modn 1000000007
char str[1010];
int main(void)
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        long long ans=0;
        scanf("%s",str);
        int i=0;
        while(str[i])
        {
            while(isdigit(str[i]))
            {
                ans=(ans*10+(str[i++]-'0'))%modn;
            }
            if(str[i]=='(')
            {
                i++;
                long long tmp=0,multi=1;
                while(isdigit(str[i]))
                {
                    tmp=(tmp*10+(str[i++]-'0'))%modn;
                    multi=(multi*10)%modn;
                }
                i+=5; //跳过" )#(b) ",一共五位,然后i-2读。
                int time=str[i-2]-'0';
                while(time--)
                    ans=(ans*multi+tmp)%modn;
            }
        }
        int p=ans;
        printf("%d\n",p );
    }
    return 0;
}

代码用时15分钟。
原比赛用时1小时以上,没看见b只有一位,导致写的程序复杂还充满bug。

1003 Pokémon GO (HDU 6146) (递推)

给出数据组数t(100),每组有一个n(10000),表示2*n的格子。
求不重复地走完所有格子的方案数(可以斜走,起始结束点任意)。
结果对1e9+7取模。

递推序列A[i],表示从左上角出发回到左下角的方案数。
则必定先走到最右,再走回最左,每一列有两种选择(去时走上还是走下)。
即A[i]=1<<(i-1)。

递推序列B[i],表示从左上角出发在任意点结束的方案数。
递推时,考虑如何由旧状态向新状态转移,B[i]的新旧状态区别为多了一列,我们将第一列视为新加入,需要排除它的干扰。
按走左下角的步数分类,而左下角只能在第一步,第二步,或者最后一步到达。
第一步走,2*B[i-1];
第二步走,4*B[i-2];(第一步走到第二列上或下)
最后一步走,即返回左下角,A[i];
所以B[i]=2*B[i-1]+4*B[i-2]+A[i]

计算序列f[i],表示任意出发任意结束的方案数。
按起点所在列分类,在边缘的情况有4*B[i]。
不在边缘:
发现总会走完该列一侧之后经过该列返回另一侧。
设先走完一侧有i列(包括起始列),方案数为A[i],除起点所在列外剩余n-i 列,方案数2*B[n-i](计算B时上或下开始),先后顺序掉转方案数为2,起点上或下方案数为2。

f[i]=4*B[i]+8*∑(A[i]*B[n-i]),1 特判f[1]=2即可。

//如果不打表复杂度能降低100倍
#include 
#include 
#define MOD 1000000007
#define M 10010
using namespace std;
long long a[M], b[M], f[M];
void init()
{
    a[1] = 1;a[2] = 2;
    b[1] = 1;b[2] = 6;
    f[1] = 2;f[2] = 24;
    for(int i = 3; i < M; i++)
    {
        a[i] = (a[i - 1] << 1) % MOD;
        b[i] = (2 * b[i - 1] + 4 * b[i - 2] + a[i]) % MOD;
        for(int j = 2; j < i; j++)
        {
            f[i] = (f[i] + 8 * a[j] * b[i - j]) % MOD;
        }
        f[i] = (f[i] + 4 * b[i])  % MOD;
    }

}

int main(void)
{
    init();
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        cout << f[n] << endl;
    }
    return 0;
}

代码用时,30分钟,因为找了好多bug。
训练了递推和分析问题的思维。

你可能感兴趣的:(题解)