题目链接
http://acm.fzu.edu.cn/problem.php?pid=2289
题目
520要到了,Xenon打算送给Cherry一条项链,这条项链有m个镶孔,编号分别为0到m-1。Xenon手上有n种颜色不同的钻石,他想将钻石镶嵌在项链上,而且每个相邻的镶孔,镶嵌上的钻石颜色要不一样。
Xenon想知道他可以镶嵌出多少种不同的项链。
PS:第k号镶孔和第(k-1+m)%m以及(k+1+m)%m号镶孔这两个镶孔是相邻关系。假设m=9,那么0号和1号、8号相邻,3号和2号、4号相邻。
两条项链不同当且仅当存在编号k,两条项链的k号镶孔的钻石颜色不一样。
Input
题目包含多组测试数据,每组测试数据包含两个正整数n和m,分别表示钻石的颜色种数和一条项链所需要的钻石个数,以空格隔开。
n≤50,m≤10^18
Output
输出一个整数,表示Xenon可以制作出多少种项链。
由于答案很大,请将答案对1000000007(10^9+7)取余。
Sample Input
5 2
Sample Output
20
分析
当m=1,ans=n.
当m=2,ans=n*(n-1)
当m=3,ans=n*(n-1)*(n-2)
设d[m]表示由最多n种颜色组成的长度为m的相邻不同色项链。
从长为m-1进行推导:
加一个钻石,需要考虑所加钻石与第1个钻石是否一样,与第m-1个钻石是否一样。
如果第1个钻石与第m-1个钻石一样,那么第m-2个钻石因为相邻不同色原则一定会与第m-1个钻石不一样,即第m-2个钻石与第1个钻石不一样。故前m-2个钻石的组成的项链总数恰好满足d[m-2]。所加钻石颜色有n-1种选择,方案数为(n-1)*d[m-2]。
如果第1个钻石与第m-1个钻石不一样,那么前m-1个钻石组成的项链总数恰好为d[m-1],所加钻石颜色有n-2种选择,方案数为(n-2)*d[m-1]。
故d[m]=(n-2)*d[m-1]+(n-1)*d[m-2],m>=4时。
m=3时不满足上述递推公式,是因为当m=3时第1个钻石与第2个钻石(即第1个钻石与第m-1个钻石)一定不一样。
m最大为1e18.用矩阵快速幂求递推即可。
ps:64位输入输出不支持%lld,天秀。
AC代码
#include <cstdio>
#include <queue>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn=1e5+100;
const ll mod=1e9+7;
struct matrix
{
ll mat[2][2];
};
matrix mul_mod(matrix A,matrix B)
{
matrix ans;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
ans.mat[i][j]=0;
for(int k=0;k<2;k++)
{
ll tmp=A.mat[i][k]*B.mat[k][j]%mod;
ans.mat[i][j]=(ans.mat[i][j]+tmp)%mod;
}
}
return ans;
}
matrix pow_mod(matrix A,ll n)
{
matrix ans=A,x=A;
n--;
while(n>0)
{
if(n&1) ans=mul_mod(ans,x);
n>>=1;
x=mul_mod(x,x);
}
return ans;
}
int main()
{
ll n,m;
while(~scanf("%I64d%I64d",&n,&m))
{
matrix A;
if(m<=3)
{
if(m==1) printf("%I64d\n",n%mod);
else if(m==2)printf("%I64d\n",n*(n-1)%mod);
else if(m==3) printf("%I64d\n",n*(n-1)*(n-2));
else printf("0\n");
continue;
}
A.mat[0][0]=(n-2)%mod;
A.mat[0][1]=1;
A.mat[1][0]=(n-1)%mod;
A.mat[1][1]=0;
matrix ans;
ans=pow_mod(A,m-3);
matrix tmp;
tmp.mat[0][0]=n*(n-1)*(n-2)%mod;
tmp.mat[0][1]=n*(n-1)%mod;
ans=mul_mod(tmp,ans);
printf("%I64d\n",ans.mat[0][0]%mod);
}
return 0;
}