您的位置:首页 > 其它

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

2017-08-21 08:55 253 查看

写在前面

我的第三篇博客:补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 <cstdio>
#include <cctype>
#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<i<n

特判f[1]=2即可。

//如果不打表复杂度能降低100倍
#include <cstdio>
#include <iostream>
#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
<< endl;
}
return 0;
}


代码用时,30分钟,因为找了好多bug。

训练了递推和分析问题的思维。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: