Description
横一划竖一划,横一划竖一划…………小R画出了一个n*m的棋盘。
由于NOIP快要到了,小R有了一个奇妙的想法。
在棋盘的每一个小方格中填入N,O,I,P这4个字母中的一个,若棋盘中每一个2*2的小棋盘中都有N,O,I,P这4个字母,小R就认为这个棋盘是幸运棋盘。小R想知道一共有多少种不同的幸运棋盘。由于这个结果可能会很大,你只需输出对1,000,000,007取模后的值。
Input
两个整数n,m表示棋盘的大小。
Output
一个整数表示幸运棋盘的个数对1,000,000,007取模后的值。
Sample Input
2 3
Sample Output
48
Data Constraint
Hint
对于30%的数据,n,m≤10
对于70%的数据,n,m≤1,000,000
对于100%的数据,2≤n,m≤2,000,000,000
.
.
.
.
.
.
分析
22的方格中有24种不同的方案(具体可以自己去试一下)
我们假设把一个22的方格像右延长一格:
再把它先按照2*2填上数字(字母)
因为红色格子左边的两个格子填上了2和3,所以这两个格一定得填1 4或4 1
由于22的格子有24种,红框内又有两种可能,所以23的方案种数就是24*2=48种。
同理,竖着也是一样。
那么怎么计算总和呢?
我们在填红蓝框的时候,有可能会出现一些重复和不成立的方案,
其实很简单就可以看出,问号所在的格子的其它周围的格子的值都是已知的,所以问号只能填1,其它也同理。
也就是说,红蓝框的方案数相加,由于图中“?”处的方案是确定的,所以要减1
而当n=2或m=2时由于它的框横向或纵向延长,所以不需要减去“?”处的1
最后,方案数公式:
- 当n=2且m=2时,ans=24
- 当n=2且m!=2时,ans=2m-2 *24
- 当m=2且n!=2时,ans=2n-2 *24
- 若非上述情况,则ans=(2n-2+2m-2-1) *24
.
.
.
.
.
程序:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long ksm(long long a,long long b,long long p)
{
long long ans=1;
for (;b;b>>=1)
{
if (b&1) ans=(long long)ans*a%p;
a=(long long)a*a%p;
}
return ans;
}
int main()
{
long long n,m,p=1000000007,ans;
scanf("%lld%lld",&n,&m);
if (n==2&&m==2) ans=24; else
if (n==2) ans=((long long)ksm(2,m-2,p)*24)%p; else
if (m==2) ans=((long long)ksm(2,n-2,p)*24)%p; else
ans=((long long)ksm(2,n-2,p)+ksm(2,m-2,p)-1)*24%p;
printf("%lld",ans);
return 0;
}