jzoj 3847. 都市環遊(travel) (Standard IO)

Description
因爲SJY乾的奇怪事情過多,SJY收到了休假的通知,於是他準備在都市間來回旅遊。SJY有一輛車子,一開始行駛性能爲0,每過1時間行駛性能就會提升1點。每個城市的道路都有性能要求。SJY一共有t時間休息,一開始他位於1號城市(保證1號城市道路要求爲0),他希望在n號城市結束旅程。每次穿過一條城市間的路會花費1時間,當然他也可以停留在一個城市不動而花費1時間。當且僅當車子的行駛性能大於等於一個城市,我們才能到達那裏。SJY希望知道,旅遊的方案模10086後的答案。(只要在某一時刻通過的道路存在一條不相同,就算不同的方案)

Input
第一行三個數n,m,t,表示有n個城市m條道路t時間。
第二行n個數,hi表示第i個城市的道路性能要求。
第三到m+2行,每行兩個數u,v,表示城市u與城市v之間有一條單向道路連接(可能有重邊)。

Output
包括一個數字,表示旅遊的方案模10086。

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

Sample Output
245

Data Constraint
對於20%的數據,n<=10,t<=80;
對於50%的數據,n<=30,t<=80;
對於100%的數據,n<=70,m<=1000,t<=100000000,hi<=70。

//written by zzy

題目大意:

給你個圖,有nn個城市,mm條邊,每個城市至少要第h[i]h[i]時間後才能經過,
走一條邊或呆在當前城市裏都會花費時間11,
求在第tt時間時到第nn城市的方案數。

題解:

對於50%的數據,n<=30,t<=80n<=30,t<=80,可以考慮dp,
f[i][j]f[i][j]表在第 ii 時間到第 jj 城市的方案數,a[i][j]a[i][j]表讀入時城市 ii 到城市 jj 的方案數
易推f[i][j]=f[i1][k]a[k][j],(1<=k<=n)f[i][j]=∑f[i-1][k]*a[k][j],(1<=k<=n) //從在第 ii 時間從城市 kk 到城市 jj

考慮滿分作法,
發現 h[i]<=70h[i]<=70 ,即在第 7070 時間後沒有限制,可以隨便走,
那麼每次矩陣 ff 都會乘上矩陣 aa

( aa [i,j] =a[i,k]a[k,j]a*a~[i,j]~=∑a[i,k]*a[k,j],即枚舉 kk ,從 iikk 再走到 jj 的方案數,
也即走兩個時間從 iijj 的方案數
那麼 ata^t 即走 tt 個時間從 iijj 的方案數)

用dp處理前 7070 時間和用矩陣快速冪後 7070 的時間
因爲矩陣乘法有結合律
再令 ff 與 ·at-70 相乘,
答案爲 f[t+1][n]f[t+1][n]

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 75
#define T 85
#define Mod 10086
using namespace std;

int i,j,k,n,l,t,x,y;
int h[N],f[T][N];

struct Mal{
	long long m[N][N];
};

Mal a,b,ans;

Mal mult(Mal x,Mal y) {
    Mal re;
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=n;j++)
	  re.m[i][j]=0;
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=n;j++)
	  for (int k=1;k<=n;k++)
	   re.m[i][j]=(re.m[i][j]+(x.m[i][k]*y.m[k][j])%Mod)%Mod;
	return re;
}

void mal_ksm(long long p) {
	for (int i=1;i<=n;i++)
	 ans.m[i][i]=1;
	while (p) {
		if (p&1) ans=mult(ans,a);
		p>>=1;
		a=mult(a,a);
	}
}

int main()
{
	scanf("%d%d%d",&n,&l,&t);
	for (i=1;i<=n;i++)
	 scanf("%d",&h[i]);
	for (i=1;i<=l;i++) {
		scanf("%d%d",&x,&y);
		a.m[x][y]++;
	}
	f[0][1]=1;
	for (i=1;i<=n;i++) a.m[i][i]=1;
	for (i=1;i<=min(t,70);i++) 
	 for (j=1;j<=n;j++)
	  if (h[j]<=i)
	  for (k=1;k<=n;k++)
	   f[i][j]=(f[i][j]+(f[i-1][k]*a.m[k][j])%Mod)%Mod;
	if (t<=70) {
	    printf("%d",f[t][n]); return 0;
	}
	mal_ksm(t-70);
	a=ans;
	for (j=1;j<=n;j++)
	 for (k=1;k<=n;k++)
	  f[71][j]=(f[71][j]+(f[70][k]*a.m[k][j])%Mod)%Mod;
	printf("%d",f[71][n]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章