题意
Sol
mdzz这题真的太恶心了。。
首先不难看出这就是个高斯消元解方程的板子题
\(f[x] = \sum_{i = 1}^n f[to(x + i)] * p[i] + ave\)
\(ave\)表示每次走的期望路程
然后一件很恶心的事情是可以来回走,而且会出现\(M > N\)的情况(因为这个调了两个小时。。)
一种简单的解决方法是在原序列的后面接一段翻转后的序列
比如\(1 \ 2 \ 3 \ 4\)可以写成\(1 2 3 4 3 2\)
然后列式子解方程就行了
附送一个数据生成器
#includeusing namespace std; int main() { freopen("a.in", "w", stdout); srand((unsigned)time(NULL)); int T = 30; printf("%d\n", T); while(T--) { int N = rand() % 100 + 1, M = rand() % 20 + 1, Y = rand() % N, X = rand() % N, D = rand() % 2; if(X == 0 || X == N - 1) D = -1; printf("%d %d %d %d %d\n", N, M, Y, X, D); int res = 100; for(int i = 1; i <= M - 1; i++) { int rd; if(res == 0) rd = 0; else rd = rand() % res + 1; printf("%d ", rd); res -= rd; } printf("%d\n", res); } return 0; }
#include#define LL long long using namespace std; const int MAXN = 1001, mod = 998244353; const double eps = 1e-9; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N, M, X, Y, D, Lim, vis[MAXN]; double g[MAXN][MAXN], p[MAXN], ave; int Gauss() { for(int i = 1; i < Lim; i++) { int mx = i; for(int j = i + 1; j < Lim; j++) if(fabs(g[j][i]) > fabs(g[mx][i])) mx = j; swap(g[i], g[mx]); //assert(g[i][i] > eps); if(fabs(g[i][i]) < eps) return -1; for(int j = i + 1; j < Lim; j++) { double p = g[j][i] / g[i][i]; for(int k = i + 1; k <= Lim; k++) g[j][k] -= g[i][k] * p; } } for(int i = 1; i < Lim; i++) if(fabs(g[i][i]) < eps) return -1; for(int i = Lim - 1; i >= 1; i--) { g[i][i] = g[i][Lim] / g[i][i]; for(int j = i - 1; j >= 1; j--) g[j][Lim] -= g[j][i] * g[i][i], g[j][i] = 0; } } int walk(int a, int b) { b %= (Lim - 1); int x = a + b; if(x <= Lim - 1) return x; return x % (Lim - 1); } void init() { memset(g, 0, sizeof(g)); memset(vis, 0, sizeof(vis)); ave = 0; } void BFS() { queueq; q.push(X); vis[X] = 1; while(!q.empty()) { int x = q.front(); q.pop(); for(int i = 1; i eps) { int t = walk(x, i); if(!vis[t]) q.push(t), vis[t] = 1; } } } } void solve() { init(); N = read(); M = read(); Y = read() + 1; X = read() + 1; D = read(); Lim = (N << 1) - 1; for(int i = 1; i 0 || (D == -1 && X > Y)) X = N - X + 1, Y = N - Y + 1; BFS(); for(int i = 1; i <= 2 * N - 2; i++) { g[i][i] = 1; if(!vis[i]) {g[i][Lim] = 3e18; continue;} if(i == Y || (Lim - i + 1 == Y)) continue; g[i][Lim] = ave; for(int j = 1, t; j <= M; j++) { t = walk(i, j); g[i][t] -= p[j]; } } if((!vis[Y] && !vis[Lim - Y + 1]) || (Gauss() == -1)) puts("Impossible !"); else printf("%.2lf\n", g[X][X]); } int main() { //freopen("a.in", "r", stdin); //freopen("b.out", "w", stdout); for(int T = read(); T; T--, solve()); return 0; }