提交时,注意选择所期望的编译器类型。
思考过程,拿到该题首先想到可以深度为n的穷举来完成,看到时间限制和数据规模,这可能要跑n年。初步判断,所用时间不可能大于O(n).小白我完全没有思路了,看了别人的答案后,发现了算法真的太神奇了,又深深的爱上了它。这道题用的是矩阵快速幂和我暂时所认为的dp思想,我自己认为中间之所以会用到矩阵的快速幂原因在于DP中的一种特殊形式,该题如果要用dp思想来构建,首先想的是1.以什么样的状态顺序进行 2.底层状态是否可以透明 3.如何表示dp的状态。dp状态的确定一般dp的本身是答案所求,不妨令其为方法数,再考虑用几维的dp,一般不超过2维,先从2维想起吧,那么这么想我可以让假设dp[i][j],其中i为层数,j可以用来表示向上的点数。这样是可以解决的,但是这道题n之大,二维的必须舍弃,然后再想一下,其实前面状态和我现在要讨论的状态其实是可以忽略的,因为都归纳到我现在的要讨论的状态中。所以用一个1维的dp即可。
该题的主要思想是这样的,首先对于4,我们可以再最后乘4的n次幂。用一个1行6列的数组dp[j]来描述前一层点数j朝上时方案的总数(当然要*4的相应的幂数才是),6次累加便可得到总数。现在假设该层朝上的为i,那我得保证i相对的那一面 (i+2)%6+1与我的前一层向上的点数(假设为j)不能是我上面输入的限制,现在假设 (i+2)%6+1与j不能相贴,也就是在我这一层的状态dp记录中,dp[i] 为上一层dp的不包括dp[j]的累加。最后再把该dp[i]确定下来,如此反复需要6*6次。发现没有,在这个过程当中,很像我们的矩阵乘法,加与不加其实是一种乘0或1的选择,这样的一种选择在每一层中都是重复的,所以我们建立起了一个方阵,judge[6][6],其中1表示取,0表示不取。现在的难点落在了如何去构造这样的judge选择矩阵。我们把judge抽象为judge[i][j],dp*judge中,j的数目是决定我们乘出来后的列数,乘出来后的新的dp中j的意义就变为向上的点数,也就是我们在这里要把judge中的j定义为该层向上的点数。那么i要表示什么呢?如果j确定,那么接下来就是dp[k]*judge[k][j]来确定新的dp中的dp[j],可以发现我们这里的i,需要把它定义为上一层向上的点数!!这样judge的定义就结束了,接下来把问题放在在哪放0,综上judge[i][j]表示为该层骰子向上点数为j时,其上一层骰子点数向上为i时,是不是两个骰子会互相排斥,这里(j ,i)和我们输入的排斥对还是不一样的,假设输入的为(a,b),这里需要把j相对应的位置定位(a+2)%6 +1和(b+2)%6 +1。到这里问题基本解题思路就解决得差不多。接下来就是快速幂的算法,可以发现当n层时dp = dp*pow(judge,n-1).在这里就涉及到了矩阵快速幂,在最后乘上pow(4,n)也运用到了整数的快速幂。这道题看了小白我一个晚上,因为在此之前不知道快速幂这种事情,还有judge的定义很费解。看了这么久,发现内容很丰富,有必要总结一波。
接下来是我自己写的代码,按理说应该没问题。有问题,多谢指正。
#include
using namespace std;
#define N (int)(1e9 + 7)
#define ll long long
int test_times = 0;
#define Debug
class Matrix
{
public:
ll mp[7][7];
Matrix( int line,int column,const int data)
{
int i,j;
mline = line;
mcol = column;
for(i = 1;i <= line;i++)
{
for(j = 1;j <= column;j++)
{
mp[i][j] = data;
}
}
}
Matrix(int);
Matrix(Matrix &);
Matrix operator *(const Matrix & m1);
void operator ^=(int n);
//void operator = (Matrix&);
friend ostream & operator <<(ostream & out,Matrix &t1);
private:
int mline,mcol;
};
Matrix::Matrix(int line)
{
int i;
mline = line;
mcol = line;
memset(mp,0,sizeof(mp));
for(i = 1;i <= line;i++)
{
mp[i][i] = 1;
}
}
Matrix::Matrix(Matrix &t)
{
mline = t.mline;
mcol = t.mcol;
for(int i = 1;i <= t.mline;i++)
{
for(int j = 1;j <= t.mcol;j++)
{
mp[i][j] = t.mp[i][j];
}
}
}
Matrix Matrix::operator *(const Matrix & m1)
{
int i,j,k;
Matrix temp(mline,m1.mcol,0);
if(mcol != m1.mline)
{
cout << "error" << endl;
system("pause");
exit(0);
}
for(i = 1;i <= mline;i++)
{
for(j = 1;j <= m1.mcol;j++)
{
for(k = 1;k <= mcol;k++)
{
temp.mp[i][j] = (temp.mp[i][j]+(mp[i][k] * m1.mp[k][j])%N)%N;
}
}
}
return temp;
}
//快速幂
void Matrix::operator ^=(int n)
{
Matrix res(6);
Matrix *t = this;
while(n)
{
if(n & 1)
{
res = res * *t;
}
n >>=1;
*t = (*t) * (*t);
}
*t = res;
}
/*
void Matrix::operator =(Matrix &m1)
{
mline = m1.mline;
mcol = m1.mcol;
for(int i = 1;i <= m1.mline;i++)
{
for(int j = 1;j <= m1.mcol;j++)
{
mp[i][j] = m1.mp[i][j];
}
}
}
*/
ostream & operator <<(ostream & out,Matrix &t1)
{
int i,j;
for(i = 1;i <= t1.mline;i++)
{
for(j = 1;j <= t1.mcol;j++)
{
out << t1.mp[i][j] << " ";
}
out << endl;
}
return out;
}
long long quick_pow(long long int a,long long int b)
{
ll res = 0;
while(b)
{
if(b&1)
{
res += a;
#ifdef Debug
test_times++;
#endif
}
a = (a*a)%N;
b >>= 1;
}
return res;
}
void test_1()
{
Matrix m1(6,6,1);
Matrix m2(m1);
m1 = m1*m2;
cout << m1;
}
void test_2()
{
Matrix m1(6,6,1);
Matrix m2(m1);
m1^=10000000;
cout << m1;
}
void solve()
{
int i;
int n;
int m;
ll res = 0;;
Matrix pos_num(1,6,1);
Matrix judge(6,6,1);
cin >> n;
cin >> m;
for(i = 1;i<=m;i++)
{
int temp_x,temp_y;
cin >> temp_x >> temp_y;
judge.mp[temp_x][(temp_y+2)%6 + 1 ] = 0;
judge.mp[temp_y][(temp_y+2)%6 + 1] = 0;
}
judge ^= (n-1);
pos_num = pos_num * judge;
for(i = 1;i <= 6;i++)
{
res = (res + pos_num.mp[1][i])%N;
}
res = (res * quick_pow(4,n))%N;
cout << res;
}
int main()
{
//test_1();
//test_2();
solve();
system("pause");
return 0;
}