题目
题意
给定一个二维坐标系和一些线段,求从 ( 0 , 0 ) (0,0) (0,0) 走到 ( k , 0 ) (k,0) (k,0) 的方案总数。若当前坐标为 ( x , y ) (x,y) (x,y),下一步可以拓展到 ( x + 1 , y + 1 ) 、 ( x + 1 , y ) 、 ( x + 1 , y − 1 ) (x+1,y+1)、(x+1,y)、(x+1,y-1) (x+1,y+1)、(x+1,y)、(x+1,y−1)。注意不能超出给出的线段——即为上边界。线段间没有重叠和空隙,保证最后一条线段覆盖 k k k。
首先,可以想到一个 d p dp dp,定义 d p [ i ] [ j ] dp[i][j] dp[i][j] 为走到 ( i , j ) (i,j) (i,j) 的方案数,那么转移就很显然了: d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j + 1 ] dp[i][j]=dp[i-1][j-1]+dp[i-1][j]+dp[i-1][j+1] dp[i][j]=dp[i−1][j−1]+dp[i−1][j]+dp[i−1][j+1],注意判断边界即可。
然而, k < = 1 e 18 k<=1e18 k<=1e18,显然 T T T 到没朋友。看到这么大的数据范围,首先想到——能否用矩阵加速呢?但是,右矩阵应该是在随着上边界而不断改变的啊,怎么办呢?考虑到不同上边界之间是递推的关系,而上边界的个数 < = 100 <=100 <=100,做上边界个数次矩阵快速幂即可。
时间复杂度 O ( n ∗ l o g ( k ) ∗ c [ i ] 3 ) O(n*log(k)*c[i]^3) O(n∗log(k)∗c[i]3),大概在 2 e 7 2e7 2e7 左右,跑过绰绰有余。
Code:
struct Matrix
{
LL n, m, c[MAXN][MAXN];
Matrix(){memset(c, 0, sizeof c);}
void Clear(){memset(c, 0, sizeof c);}
friend Matrix operator *(Matrix A,Matrix B)
{
Matrix Res;
// Res.Clear();
Res.n = A.n, Res.m = B.m;
for (Int k = 1; k <= B.n; ++ k)
for (Int i = 1; i <= A.n; ++ i)
for (Int j = 1; j <= A.m; ++ j)
if ( B.c[k][j] )
Res.c[i][j] += A.c[i][k] * B.c[k][j] % Mod,
Res.c[i][j] %= Mod;
return Res;
}
void Print()
{
for (Int i = 1; i <= n; ++ i, putchar('\n'))
for (Int j = 1; j <= m; ++ j)
printf("%lld ", c[i][j]);
}
}A, B, C;
inline Matrix QuickPow(Matrix x,LL y)
{
Matrix Temp;
// Temp.Clear();
Temp.n = Temp.m = x.m;
for (Int i = 1; i <= x.m; ++ i)
Temp.c[i][i] = 1;
while ( y )
{
if (y & 1)
Temp = Temp * x;
x = x * x;
y /= 2;
}
return Temp;
}
int main()
{
LL n, k;
read( n ); read( k );
B.n = B.m = C.n = C.m = 16;
for (Int i = 1; i <= 16; ++ i)
C.c[i][i] = 1;
for (Int i = 1; i <= n; ++ i)
{
LL a, b, c;
read( a ); read( b ); read( c );
c ++;
b = Min(b, k);
B.Clear();
for (Int y = c; y >= 1; -- y)
{
if (y != c)
B.c[y][y + 1] = 1;
B.c[y][y] = 1;
if (y != 1)
B.c[y][y - 1] = 1;
}
// B.Print();
C = C * QuickPow(B, b - a);
}
A.n = 1, A.m = 16;
A.c[1][1] = 1;
A = A * C;
printf("%lld", A.c[1][1]);
return 0;
}