题目描述:
给出一个R行C列的空白表格,在表格的左上方第一个格子处放了一枚骰子。骰子有六个面,分别有1,2,3,4,5,6这六个数字,其中,相反两面的数之和为7.骰子初始的时候是这样放置的,上面为1,右侧那一面为3。现在将骰子进行下面4种操作:
1.往右滚动,直到达到最后一列。
2.往下滚动,达到下一行
3.往左滚动,直到达到第一列。
4.往下滚动,到达到下一行。
现在你按照上面的4种操作,依次进行,直到将所有格子都走一遍。每走到一个格子上,将骰子最上方那面的数字记下来。最后,求出所有记下来的数字之和。
输入:
两个整数R,C.(R,C均为小于100000的正整数)
输出:
所有数字之和。
50%的数据,R,C均小于100.
输入样例1:
3 2
输出样例1:
19
输入样例2:
3 4
输出样例2:
42
输入样例3:
737 296
输出样例3:
763532
样例1解释:
|
1 |
4 |
|
1 |
5 |
|
3 |
5 |
最初思路:通过循环求出骰子在表格中滚动产生的循环,并以此规律求解。但保存规律使用的二维数组容量不够,并且时间复杂度很高,所以只过了一半左右的数据。程序如下:
#include<cstdio>
#include<iostream>
using namespace std;
long long r,c;
long long looplen;
long long loopsum;
char loop[2000][2000];
bool flag = true;
void findloop()
{
int up=1, front=2, right=3;
int tu, tf, tr;
bool dir = true;
int i, j, k;
for (i=1; i<=r; ++i)
{
if (dir)
{
for (j=1; j<=c; ++j)
{
tu=up, tf=front, tr=right;
loop[i][j] = up;
if (j<c)
up = 7-tr, right = tu;
else
up = 7-tf, front = tu;
}
}
else{
for (j=c; j>=1; --j)
{
tu=up, tf=front, tr=right;
loop[i][j] = up;
if (j>1)
up = tr, right = 7-tu;
else
up = 7-tf, front = tu;
}
}
dir = !dir;
if (i > 1)
{
bool bl = true;
for (k=1; k<c; ++k)
if (loop[1][k]!=loop[i][k])
{
bl = false;
flag = false;
break;
}
if (bl)
{
looplen = i-1;
break;
}
}
}
if (!flag)
{
for (i=1; i<=looplen; ++i)
for (j=1; j<=c; ++j)
loopsum += loop[i][j];
}
}
int main()
{
//freopen("dice.in","r",stdin);
//freopen("dice.out","w",stdout);
int i, j;
cin >> r >> c;
findloop();
if (looplen)
{
long long ans = loopsum*(r/looplen);
for (i=1; i<=r%looplen; ++i)
for (j=1; j<=c; ++j)
ans += loop[i][j];
cout << ans;
}
else
{
long long ans=0;
for (i=1; i<=r; ++i){
for (j=1; j<=c; ++j)
ans += loop[i][j];
}
cout << ans;
}
}
在写以上程序时,由于没有注意到输入数据可能不到一个循环的情况,looplen变量可能为0,作为除数会爆运行错误,这个地方花了接近两个小时才发现。
考完后,发现一大牛用500+b就把这道题A了。他提供的解法是:将每一次横向滚动的次数优化(横向滚动时每四次就会产生一次循环,每次循环时骰子朝上的面值之和为14),这样优化后最坏的时间复杂度为O(3n),因此完全可以过本题的所有数据。
我按这种算法写出的代码如下:
#include<iostream>
using namespace std;
long long r,c,ans;
int main()
{
cin >> r >> c;
bool dir = true;
int i, j;
int up=1, front=2, right=3;
int tu, tf, tr;
for (i=1; i<=r; ++i)
{
if (dir)
{
ans += c/4*14;
for (j=c/4*4+1; j<=c; ++j)
{
ans += up;
tu=up, tf=front, tr=right;
if (j<c) up = 7-tr, right = tu;
else up = 7-tf, front = tu;
}
dir = !dir;
}
else{
ans += c/4*14;
for (j=c-c/4*4; j>=1; --j)
{
ans += up;
tu=up, tf=front, tr=right;
if (j>1) up = tr, right = 7-tu;
else up = 7-tf, front = tu;
}
dir = !dir;
}
}
cout << ans;
}
以后做这种题,要想好最佳解法了再写代码,免得走很多弯路。写代码的时候也应该保持清醒,不要犯一些低级错误。
2万+




被折叠的 条评论
为什么被折叠?



