BZOJ-1875 HH去散步 DP+矩陣乘法快速冪

1875: [SDOI2009]HH去散步
Time Limit: 20 Sec Memory Limit: 64 MB
Submit: 1196 Solved: 553
[Submit][Status][Discuss]

Description
HH有個一成不變的習慣,喜歡飯後百步走。所謂百步走,就是散步,就是在一定的時間 內,走過一定的距離。 但是同時HH又是個喜歡變化的人,所以他不會立刻沿着剛剛走來的路走回。 又因爲HH是個喜歡變化的人,所以他每天走過的路徑都不完全一樣,他想知道他究竟有多 少種散步的方法。 現在給你學校的地圖(假設每條路的長度都是一樣的都是1),問長度爲t,從給定地 點A走到給定地點B共有多少條符合條件的路徑

Input
第一行:五個整數N,M,t,A,B。其中N表示學校裏的路口的個數,M表示學校裏的 路的條數,t表示HH想要散步的距離,A表示散步的出發點,而B則表示散步的終點。 接下來M行,每行一組Ai,Bi,表示從路口Ai到路口Bi有一條路。數據保證Ai = Bi,但 不保證任意兩個路口之間至多隻有一條路相連接。 路口編號從0到N − 1。 同一行內所有數據均由一個空格隔開,行首行尾沒有多餘空格。沒有多餘空行。 答案模45989。

Output
一行,表示答案。

Sample Input
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2

Sample Output
4

HINT
對於30%的數據,N ≤ 4,M ≤ 10,t ≤ 10。 對於100%的數據,N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B

Source
Day1

其實這題應該不難,但是真的沒想到正解....

題解:
正常是對點構造矩陣,那麼這裏用邊來構造,保證走的時候不經過反向邊即可,然後矩乘快速冪加速

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define maxn 25
#define maxm 70
#define p 45989
int n,m,t,st,ed;
struct data{int to,next;}edge[maxm*2];
int head[maxm],cnt;
int l,ans;
struct Mat{int a[maxm*2][maxm*2];Mat(){memset(a,0,sizeof(a));}};

void add(int u,int v)
{
    cnt++;
    edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;
}

Mat mul(Mat A,Mat B)
{
    Mat re;
    for (int i=1; i<=l; i++)
        for (int j=1; j<=l; j++)
            for (int k=1; k<=l; k++)
                re.a[i][j]=(re.a[i][j]+(A.a[i][k]*B.a[k][j])%p)%p;
    return re;              
}

Mat quick_mul(Mat A,int x)
{
    Mat re;
    for (int i=1; i<=l; i++) re.a[i][i]=1;
    while (x)
        {
            if (x&1) re=mul(re,A);
            x>>=1; A=mul(A,A);
        }
    return re;
}

int findre(int x)
{
    if (x&1) return x+1;
        else return x-1;
}

int main()
{
    n=read(),m=read(),t=read(),st=read(),ed=read();
    for (int i=1; i<=m; i++)
        {
            int u=read(),v=read();
            add(u,v); add(v,u);
        }
    Mat x,y;
    for (int i=head[st]; i; i=edge[i].next)
        x.a[1][i]=1;
    l=cnt;  
    if (t==0) {if (st==ed) puts("1"); else puts("0"); return 0;}
    for (int i=1; i<=l; i++)
        for (int j=head[edge[i].to]; j; j=edge[j].next)
            if (j!=findre(i)) y.a[i][j]=1;
    x=mul(x,quick_mul(y,t-1));                          
    for (int i=head[ed]; i; i=edge[i].next)
        ans=(ans+x.a[1][findre(i)])%p;
    printf("%d\n",ans);     
    return 0;
}
發佈了164 篇原創文章 · 獲贊 9 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章