HDU 2604 Queuing (矩陣快速冪),hdu2604
HDU 2604 Queuing (矩陣快速冪)
ACM
題目地址:HDU 2604 Queuing
題意:
n個人排隊,f表示女,m表示男,包含子串‘fmf’和‘fff’的序列為O隊列,否則為E隊列,有多少個序列為E隊列。
分析:
矩陣快速冪入門題。
下面引用巨巨解釋:
用f(n)表示n個人滿足條件的結果,那麼如果最後一個人是m的話,那麼前n-1個滿足條件即可,就是f(n-1);
如果最後一個是f那麼這個還無法推出結果,那麼往前再考慮一位:那麼後三位可能是:mmf, fmf, mff, fff,其中fff和fmf不滿足題意所以我們不考慮,但是如果是
mmf的話那麼前n-3可以找滿足條件的即:f(n-3);如果是mff的話,再往前考慮一位的話只有mmff滿足條件即:f(n-4)
所以f(n)=f(n-1)+f(n-3)+f(n-4),遞推會跪,可用矩陣快速冪
構造一個矩陣:
矩陣快速冪和普通的快速冪原理是一樣的,如果不懂可以先去補補快速冪。
代碼:
/** Author: illuz <iilluzen[at]gmail.com>* Blog: http://blog.csdn.net/hcbbt* File: 2604.cpp* Create Date: 2014-08-02 21:20:18* Descripton: matrix */#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#include <cmath>#include <cstdlib>#define repf(i,a,b) for(int i=(a);i<=(b);i++)typedef long long ll;const int N = 0;const int SIZE = 4;int l, MOD;struct Mat{ll v[SIZE][SIZE];// value of matrixMat() {memset(v, 0, sizeof(v));}void init(ll _v) {repf (i, 0, SIZE)v[i][i] = _v;}};Mat operator * (Mat a, Mat b) {Mat c;repf (i, 0, SIZE - 1) {repf (j, 0, SIZE - 1) {c.v[i][j] = 0;repf (k, 0, SIZE - 1) {c.v[i][j] += (a.v[i][k] * b.v[k][j]) % MOD;c.v[i][j] %= MOD;}}}return c;}Mat operator ^ (Mat a, ll k) {Mat c;c.init(1);while (k) {if (k&1) c = a * c;a = a * a;k >>= 1;}return c;}int main() {Mat a, b, c;// aa.v[0][0] = 9;a.v[1][0] = 6;a.v[2][0] = 4;a.v[3][0] = 2;// bb.v[0][0] = b.v[0][2] = b.v[0][3] = b.v[1][0] = b.v[2][1] = b.v[3][2] = 1;while (~scanf("%d%d", &l, &MOD)) {if (l == 0) {puts("0");} else if (l <= 4) {printf("%lld\n", a.v[4 - l][0] % MOD);} else {c = b ^ (l - 4);c = c * a;printf("%lld\n", c.v[0][0] % MOD);}}return 0;}
下面是一個矩陣快速冪解斐波那契數列第n項對第m項取餘的程式,但是總是運行出錯,解
按照正常的邏輯是只要求a[2][2]={1,1,1,0}這個矩陣的n次方就可以得到斐波那契數列的第n項(即a[0][1])的值。但是你忽略了一點,就是你在求a[0][1],a[1][0],a[1][1]的值的時候你的a[0][0]的值其實已經改變了,導致你求得的a[0][1]的值不正確,繼而影響到a[1][0]和a[1][1]的值。
因此,我們在遍曆這四個值的時候是不能改變其中任何一個的,只有改完之後才能去改變它的值。所以我們可以用幾個變數先將求得的新矩陣各值存起來,如下:
#include<stdio.h>
int a[2][2]={1,1,1,0},b[2][2]={1,1,1,0};//使用兩個二維數組表示快速冪演算法要用到的矩陣
int main()
{
int n,m,i,j,t,u;
int a1,a2,a3,a4;
while(scanf("%d %d",&n,&m)!=EOF)
{
if(m==-1 && n==-1)//當輸入的m.n值為-1時結束整個演算法
return 0;
/*以下是對於第n項斐波那契數的計算*/
if(n==0)
a[0][0]=0;
else if(n==1 || n==2)
a[0][0]=1;
else
{
for(i=3;i<=n;i++)
{
a1=a[0][0]*b[0][0]+a[0][1]*b[1][0];
a2=a[0][0]*b[0][1]+a[0][1]*b[1][1];
a3=a[1][0]*b[0][0]+a[1][1]*b[1][0];
a4=a[1][0]*b[0][1]+a[1][1]*b[1][1];
a[0][0]=a1;
a[0][1]=a2;
a[1][0]=a3;
a[1][1]=a4;
}
}
t=a[0][0];
a[0][0]=1;//重設矩陣
a[0][1]=1;
a[1][0]=1;
a[1][1]=0;
if(m==0)
a[0][0]=0;
else if(m==1 || m==2)
a[0][0]=1;
else
{
for(j=3;j<=m;j++)
{
a1=a[0][0]*b[0][0]+a[0][1]*b[1][0];
a2=a[0][0]*b[0][1]+a[0][1]*b[1][1];
a3=a[1][0]*b[0][0]+a[1][1]*b[1][0];
a4=a[1][0]*b[0][1]+a[1][1]*b[1][1];
a[0][0]=a1;
a[0][1]=a2;
a[1][0]=a3;
a[1][1]=a4;
}
}
u=a[0][0];
a[0][0]=1;//重設矩陣
a[0][1]=1;
a[1][0]=1;
a[1][1]=0;
t=t%u;
printf("%d\n",t);
}
return 0;
}
還有一點,就是你的矩陣相乘後兩項寫錯了,自己對比一下改過來吧。
這樣就能得到你想要的結果了。
...餘下全文>>
哪位大蝦可以給出矩陣快速冪的c++代碼?最好有注釋,