您的位置:首页 > 其它

矩阵快速幂 zoj-3690 Choosing number

2013-04-04 11:51 281 查看
题目链接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4973

题目意思:

有n个人,有1——m个数,每个人可以选择1个数,要求相邻的两个人如果选的数相同则必须大于k,求选数的种数。

解题思路:

dp
[1]表示第n个人选大于k的数的总的种数,dp
[2]表示第n个人选<=k的数的总的种数。

则 dp
[1]=(m-k)*dp[n-1][1]+(m-k)*dp[n-1][2]

dp
[2]=k*dp[n-1][1]+(k-1)*dp[n-1][2]

构造矩阵

m-k m-k dp[n-1][1] dp
[1]

k k-1 dp[n-1][2] dp
[2]

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF (1<<30)
#define PI acos(-1.0)
using namespace std;

#define ll long long
#define mm  1000000007
/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/

//矩阵快速幂,快速幂

ll Mod(ll m,ll n)  //快速幂求m^n%mm
{
ll res=1;

while(n)
{
if(n&1)
res=(res*m)%mm;
m=(m*m)%mm;
n=n>>1;
}
return res;
}

ll save[3][3];

int main()
{
ll n,m,k;

while(scanf("%lld%lld%lld",&n,&m,&k)!=EOF)
{
if(k==0)
{
printf("%lld\n",Mod(m,n));
continue;
}
if(n==1)
{
printf("%lld\n",m);
continue;
}

save[1][1]=m-k,save[1][2]=m-k;
save[2][1]=k,save[2][2]=k-1;

ll ans1=m-k,ans2=k;
n--;

while(n)
{
if(n&1)
{
ll temp1=((save[1][1]*ans1)%mm+(save[1][2]*ans2)%mm)%mm;
ll temp2=((save[2][1]*ans1)%mm+(save[2][2]*ans2)%mm)%mm;

ans1=temp1;
ans2=temp2;
}
n=n>>1;   //以后写矩阵相乘的话直接用三个循环来写,这样写的话容易出错
ll a1=((save[1][1]*save[1][1])%mm+(save[1][2]*save[2][1])%mm)%mm;
ll a2=((save[1][1]*save[1][2])%mm+(save[1][2]*save[2][2])%mm)%mm;
ll b1=((save[2][1]*save[1][1])%mm+(save[2][2]*save[2][1])%mm)%mm;
ll b2=((save[2][1]*save[1][2])%mm+(save[2][2]*save[2][2])%mm)%mm;

save[1][1]=a1,save[1][2]=a2;
save[2][1]=b1,save[2][2]=b2;

}

printf("%lld\n",(ans1+ans2)%mm);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: