Time Limit: 3000/2000 MS (C/Others) Memory Limit: 65536/32768 K (C/Others)
本次组委会推荐使用C、C++Problem Description
原题:http://tieba.baidu.com/p/2039526366
du熊填数时有一个要求:不能存在两个相邻的1,且位于不同的层(这里的相邻指两格子共用一条线)。 请你帮du熊计算一下有多少种填法。
Input 输入包含多组测试数据,每组数据包含一个偶数n (2 <= n <= 500)。
Output 请计算并输出对2012取余后的结果。
Sample Input 2 4S
ample Output 16 1952
Hint当n = 4时 1011 0100 0100 0000是满足要求的 1111 0100 0100 0000是不满足要求的,因为第一行第二列的1和第二行第二列的1相邻且位于不同的层。
我的想法:
开始的时候,发现四个角上的四块是绝对独立的,与其他的无关。
首先,我先把正方形按照对角线分成四块相对独立直角三角形看待的,每个三角(只是看作三角)中的方块都与固定方向相邻的比较(我这里的意思是,上下两个三角形里的正方块上下比较,左右的左右比较),发现这样根本不能解决问题,因为对角线上的方块根本不允许这样做,更重要的是这样子只是减少了穷举而已,肯定绝对一定会超时,所以放弃。
then。
由于每个正方体的边数都是偶数(n),所以可以看作独立的四块,分成4个以(n/2)为边的正方体,每个正方体都是独立的。我发现了一个很简单的规律,拿左上角的大正方体举例,左上角的一个方块是独立的,接下来的与它相挨的三个方块,这三个方块作为一个整体是独立的,他们三个的01分布跟其他部分无关,然后是与这三个相挨的5个……一直到n-1个,就是1,3,5,7,9,...,n-1,堑把这称作“层”。这时问题就转换成了在01限制下,奇数连续的填法。填法其实很简单,把1和3 的列出来就能发现规律了,1的时候是两种"1","0",3的时候可以看作在1的情况下追加两个数,以后的每个奇数都可以看作上一个奇数的追加两个数,这是个很简单的规律,拿3举例,在"1"后面追加有"00""01"两种情况,在"0"后面追加有"00""01""10"三种情况,这就很明显了,我就不继续往下分析了,当这个奇数是2i-1时(第i个奇数时),填法是3^(i-1)+2^(i-1)种(^就是幂,额),因为每层都是独立的,所以从1到n-1运算出来的结果相乘,再四次幂就是问题的答案了。
对2012取余,上面这个方法涉及的都是加法或者乘法,所以取余没有限制,那么就要选择在恰当的时候对2012取余,因为取余的算法相当于>>>>a%b=a-a/b*b;所以处处都取余是不可取的,我的做法是在定义pow数组的时候取余,我认为这很必要,再就是每次大乘一下都取余一次,我没有验证是否高效。
呼,描述出自己想的真不那么简单啊,还是觉得描述的不那么清晰,毕竟是第一次,见谅。有什么不足,望指点。
下面是我的答案:
#include<iostream>
using namespace std;
int main()
{
int n;
int pow2[2012];//2的n次方对2012取余
int pow3[2012];//3的n次方对2012取余
pow2[0]=1;
pow3[0]=1;
//初始化那俩pow
for(int i=1;i<2012;i++)
{
pow2[i]=(pow2[i-1]<<1)%2012;
pow3[i]=(pow3[i-1]*3)%2012;
}
while(cin>>n)
{
if(n==0)
{
cout<<"0"<<endl;
continue;
}
int num=n>>1;
int sum = 1;
int temp;
for(int i = 0;i<num;i++)
{
temp = pow2[i] + pow3[i];
sum*=temp;
sum%=2012;
}
sum*=sum;
sum%=2012;
sum*=sum;
sum%=2012;
cout<<sum<<endl;
}
return 0;
}
你能发现这个算法的错误在哪儿吗?啊哈
错误出在每次追加两个位数的时候,我把以0结尾的乘2,以1结尾的乘2,其实以0结尾的产生三倍的数,其中三分之二仍以0结尾,另外三分之一以1结尾;而以1结尾的产生两倍于自身的数 产生的数里面以0和1结尾的各一半。可以归纳成斐波那契似的递归规律。
A(1) = 2
A(2) = 5
.
.
A(n) = 3A(n-1) - A(n-2)
B(n) = [A(1)· A(2)····A(n)]^4 mod 2012
#include<iostream>
using namespace std;
int main()
{
int n;
int a[501];
int b[501];
a[1]=2;
a[2]=5;
b[0]=0;
b[1]=2;
b[2]=10;
//初始化那a
for(int i=3;i<501;i++)
{
a[i]=(a[i-1]*3 - a[i-2])%2012;
b[i]=(b[i-1]*a[i])%2012;
}
while(cin>>n)
{
n>>=1;
int sum = (b[n]*b[n])%2012;
sum*=sum;
sum%=2012;
cout<<sum<<endl;
}
return 0;
}