妖精繁殖
题目描述
有 n n n 种小妖精,我们给这 n n n 类小妖分别编号为 1 , ⋯ , n 1,\cdots,n 1,⋯,n。
t t t 年前,一次事故造出了 n n n 只小妖(视为刚出生的,而非成熟的),这些小妖的种类互不相同。
第 i i i 种小妖出生后需要 y i y_i yi 年成熟,成熟后会立即产下 k i k_i ki 个蛋(小妖是无性繁殖的生物)然后死亡。将它的蛋编号为 1 , ⋯ , k 1,\cdots,k 1,⋯,k,其中,第 j j j 个蛋需要 h i , j h_{i,j} hi,j 年孵化,孵出的小妖的类型为 g i , j g_{i,j} gi,j。
请问,现在和祖先关系最远的小妖到了多少代,不考虑暂未孵出的。假设祖先是 1 1 1 代,其子辈为第 2 2 2 代,孙辈为第 3 3 3 代,以此类推。
题解
可以对题目中的关系建立一个有向图,每一个点代表一种小妖,边代表繁殖关系,边权代表第 i i i 中小妖从出生到繁殖出第 j j j 种小妖所需要的最小时间。设这个图的邻接矩阵为 G G G
设 d p k , i , j dp_{k,i,j} dpk,i,j 为 第 i i i 种小妖有代数为 k k k 的第 j j j 种小妖所需要的最小时间
转移:
d
p
k
,
i
,
j
=
min
1
≤
x
≤
n
d
p
k
−
1
,
i
,
x
+
G
x
,
j
dp_{k,i,j}=\min_{1\leq x\leq n}{dp_{k-1,i,x}+G_{x,j}}
dpk,i,j=1≤x≤nmindpk−1,i,x+Gx,j
这样就可以使用广义矩阵乘法了
题目求的是 t t t 年后和祖先关系最远的小妖的代数,等价于求一个最大的 k k k,使得 d p k dp_k dpk 中至少有一个数小于等于 t t t。
因为 t t t 非常大,所以使用倍增优化
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
# define int long long
# define rd(t) read <t> ()
# define mem(a, b) memset (a, b, sizeof (a))
# define fi first
# define se second
# define lc u << 1
# define rc u << 1 | 1
# define debug printf ("debug\n")
const int N = 1005;
template <typename T> inline T read ()
{
T s = 0; int w = 1; char c = getchar ();
for (; !isdigit (c); c = getchar ()) { if (c == '-') w = -1; }
for (; isdigit (c); c = getchar ()) s = (s << 1) + (s << 3) + c - '0';
return s * w;
}
int n, t;
int g[N], h[N];
struct matrix
{
int a[105][105];
matrix () { mem (a, 0x3f); }
matrix operator * (const matrix &b) const
{
matrix ans;
for (int i = 1; i < 105; i ++ )
{
for (int k = 1; k < 105; k ++ )
{
for (int j = 1; j < 105; j ++ )
ans.a[i][j] = min (ans.a[i][j], a[i][k] + b.a[k][j]);
}
}
return ans;
}
} a, f[70];
bool check (matrix a)
{
bool hav = 0;
for (int i = 1; i < 105; i ++ )
{
for (int j = 1; j < 105; j ++ )
{
if (a.a[i][j] <= t)
{
hav = 1;
break;
}
}
if (hav) break;
}
return hav;
}
signed main ()
{
n = rd (int), t = rd (int);
for (int i = 1; i <= n; i ++ )
{
int k = rd (int), y = rd (int);
for (int j = 1; j <= k; j ++ ) g[j] = rd (int);
for (int j = 1; j <= k; j ++ ) h[j] = rd (int);
for (int j = 1; j <= k; j ++ )
f[1].a[i][g[j]] = min (f[1].a[i][g[j]], y + h[j]);
}
for (int i = 2; i <= 64; i ++ ) f[i] = f[i - 1] * f[i - 1];
matrix a; mem (a.a, 0);
int ans = 0;
for (int i = 64; i >= 1; i -- )
{
matrix tmp = a * f[i];
if (check (tmp))
{
ans += (1ll << (i - 1));
a = tmp;
}
}
printf ("%lld\n", ans);
return 0;
}