题意
题目链接
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)
然后列式子解方程就行了
附送一个数据生成器
代码语言:javascript复制#include<bits/stdc .h>
using namespace std;
int main() {
freopen("a.in", "w", stdout);
srand((unsigned)time(NULL));
int T = 30;
printf("%dn", 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 %dn", 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("%dn", res);
}
return 0;
}
代码语言:javascript复制#include<bits/stdc .h>
#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() {
queue<int> q; q.push(X); vis[X] = 1;
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = 1; i <= M; i ) {
if(p[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 <= M; i ) p[i] = (double) read() / 100, ave = (double) i * p[i];
if(X == Y) {puts("0.00"); return;}
if(D > 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("%.2lfn", g[X][X]);
}
int main() {
//freopen("a.in", "r", stdin);
//freopen("b.out", "w", stdout);
for(int T = read(); T; T--, solve());
return 0;
}