女神的正多面体
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 128000/64000 KB (Java/Others)
Problem Description
EOF女神灰常喜欢整齐的东西,例如多面体中最喜欢的就是正多面体。正多面体的定义为:指每个面都是全等的正多边形的多面体。欧拉大人告诉我们,正多面体只有正四面体(正三棱锥),正六面体(立方体),正八面体(钻石?),正十二面体,还有正二十面体。后面两种太复杂了,EOF女神不喜欢。下面是前三种多面体的图片,EOF女神给每个多面体的每个顶点都编号了。
EOF女神想知道,如果从其中一个点出发,每一步可以沿着棱走到另一个顶点,k步之内从到达指定的顶点有多少种走法?(P.S.路径中只要有一个顶点不一样即视为不同的走法)。EOF女神知道结果会很庞大,因此只要知道除以1000000007的余数就可以了。
Input
先输入一个正整数T,表示测试数据的组数。
接下来是T行,每行包括四个正整数n,k,i,j,其中n∈{4,6,8},表示正多面体的种类,i为起点的编号,j为终点的编号,k为步数(k<=10^18)
Output
输出T行,每行输出一个整数,表示方法数。(记得要取余哦~)
Sample Input
3 6 1 8 4 6 2 3 1 8 3 2 4
Sample Output
1 2 12
Hint
第二组样例,有3->2->1与3->4->1两种方法
第三组样例,有2->1->4、2->3->4、2->5->4、2->6->4、2->1->3->4、2->1->5->4、2->3->1->4、2->3->6->4、2->5->1->4、2->5->6->4、2->6->3->4、2->6->5->4这12种方法
Source
mathlover
Manager
mathlover
题意明显,思路快速幂,不过得分三种情况来构造操作矩阵,构造方法全部一样。
例如对于四面体的时候假设在K步能够走到1点 Fi(k)代表第K步到i点的放法数则F1(k)=F2(k-1)+F3(k-1)+F4(k-1)说明第K-1步的时候必然在2 3 4 点 那么也就是在k-1步时2 3
4点的放法数相加,对于六面体,八面体也根据顶点的个数和到达的情况来构造矩阵,然后就这么写了,而且写的很恶心。。后来样例都没过- -结果发现这题是求K步之内到达的方法数。。直接哭瞎,一开始以为要继续构造K个sumk用来记录每种情况的和,后来大湿提醒我,只要多加终点那一维的情况就好了,然后顿悟了,然后敲了一下,过了。。。好累下午做了CF晚上又做了这个,早上还打了羽毛球,快累晕过去了。。。 赶脚状态不是很好啊TVT。。。
题意明显,思路快速幂,不过得分三种情况来构造操作矩阵,构造方法全部一样。
例如对于四面体的时候假设在K步能够走到1点 Fi(k)代表第K步到i点的放法数则F1(k)=F2(k-1)+F3(k-1)+F4(k-1)说明第K-1步的时候必然在2 3 4 点 那么也就是在k-1步时2 3
4点的放法数相加,对于六面体,八面体也根据顶点的个数和到达的情况来构造矩阵,然后就这么写了,而且写的很恶心。。后来样例都没过- -结果发现这题是求K步之内到达的方法数。。直接哭瞎,一开始以为要继续构造K个sumk用来记录每种情况的和,后来大湿提醒我,只要多加终点那一维的情况就好了,然后顿悟了,然后敲了一下,过了。。。好累下午做了CF晚上又做了这个,早上还打了羽毛球,快累晕过去了。。。 赶脚状态不是很好啊TVT。。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const long long mod=1000000007;
long long n,k,s,e;
struct juzhen {
long long m[10][10];
};
juzhen mut(juzhen a,juzhen b)
{
juzhen ans;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
ans.m[i][j]=0;
for(int k=1;k<=n;k++)
{
ans.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
ans.m[i][j]%=mod;
}
}
}
return ans;
}
juzhen pow(juzhen a,long long p)
{
juzhen ans;
memset(ans.m,0,sizeof(ans.m));
for(int i=1;i<=n;i++)
{
ans.m[i][i]=1;
}
while(p)
{
if(p%2==0)
{
a=mut(a,a);
p/=2;
}
else
{
ans=mut(ans,a);
p--;
}
}
return ans;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>k>>s>>e;
juzhen ans;
if(n==4)
{
memset(ans.m,0,sizeof(ans.m));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) ans.m[i][j]=0;
else ans.m[i][j]=1;
}
}
}
else if(n==6)
{
n=8;
memset(ans.m,0,sizeof(ans.m));
ans.m[1][2]=ans.m[1][4]=ans.m[1][5]=1;
ans.m[2][1]=ans.m[2][3]=ans.m[2][6]=1;
ans.m[3][2]=ans.m[3][4]=ans.m[3][7]=1;
ans.m[4][1]=ans.m[4][3]=ans.m[4][8]=1;
ans.m[5][1]=ans.m[5][6]=ans.m[5][8]=1;
ans.m[6][2]=ans.m[6][5]=ans.m[6][7]=1;
ans.m[7][3]=ans.m[7][6]=ans.m[7][8]=1;
ans.m[8][4]=ans.m[8][5]=ans.m[8][7]=1;
}
else if(n==8)
{
n=6;
memset(ans.m,0,sizeof(ans.m));
ans.m[1][2]=ans.m[1][3]=ans.m[1][4]=ans.m[1][5]=1;
ans.m[2][1]=ans.m[2][3]=ans.m[2][5]=ans.m[2][6]=1;
ans.m[3][1]=ans.m[3][2]=ans.m[3][4]=ans.m[3][6]=1;
ans.m[4][1]=ans.m[4][3]=ans.m[4][5]=ans.m[4][6]=1;
ans.m[5][1]=ans.m[5][2]=ans.m[5][4]=ans.m[5][6]=1;
ans.m[6][2]=ans.m[6][3]=ans.m[6][4]=ans.m[6][5]=1;
}
juzhen b;
memset(b.m,0,sizeof(b.m));
b.m[s][1]=1;//0步的时候就是原地不动的方法数为1,其余均为0,否则状态枚举又能枚举哭你。。。
n++;
for(int i=1;i<n;i++)
ans.m[n][i]=ans.m[e][i];//多加一维记录终点的情况
ans.m[n][n]=1;
b=mut(pow(ans,k),b);
cout<<b.m[n][1]<<endl;
}
return 0;
}