传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=4204
题意简述:
有
M
个球,一开始每个球均有一个初始标号,标号范围为
每次操作等概率取出一个球(即取出每个球的概率均为
1M
),若这个球标号为
k (k < N)
,则将它重新标号为
k+1
;若这个球标号为
N
,则将其重标号为
现在你需要求出,经过
K
次这样的操作后,每个标号的球的期望个数。
数据范围:
题解: 首先操作
1
次是可以轻松地
a[i][i]=m−1m,a[i][i−1]=1m(1<i≤n)
a[1][1]=m−1m,a[1][n]=1m(i=1);
是一个循环矩阵,因为循环矩阵的积还是循环矩阵,所以只要存一行即可保留整个矩阵的信息,那么矩阵乘法复杂度就只有
O(n2)
了。加上快速幂整个复杂度是
O(n2logk)
。
#include<bits/stdc++.h>
const int N = 1005;
struct matrix{double a[N];} x;
int n, m, k, a[N];
double t[N * 2];
matrix operator * (const matrix &a, const matrix &b) {
matrix c;
memset(&c, 0, sizeof(c));
for (int i = 1; i <= n; i++)
t[n + 1 - i] = t[n + n + 1 - i] = b.a[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
c.a[i] += a.a[j] * t[n - i + j];
return c;
}
matrix pow(matrix x, int k) {
matrix ret;
memset(&ret, 0, sizeof(ret));
ret.a[1] = 1;
for (; k; k >>= 1, x = x * x)
if (k & 1) ret = ret * x;
return ret;
}
int main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
x.a[1] = (double)(m - 1) / m;
x.a[n] = 1.0 / m;
x = pow(x, k);
for (int i = 1; i <= n; i++)
t[i] = t[n + i] = x.a[i];
for (int i = 1; i <= n; i++) {
double ans = 0;
for (int j = 1; j <= n; j++)
ans += a[j] * t[n - i + j + 1];
printf("%.3f\n", ans);
}
return 0;
}