1. 题目描述
K沿着$0,1,2,cdots,n-1,n-2,n-3,cdots,1,$的循环节不断地访问$[0, n-1]$个时光结点。某时刻,时光机故障,这导致K必须持续访问时间结点。故障发生在结点x处,方向为d,
在访问k个结点后时光机以概率$P_k%$的概率修复好,k不超过m。求当K最终访问结点Y时经过的时光结点的期望。
2. 基本思路
上述循环节包含包含$nn = 2n-2个$元素(因此,尤其需要特判n=1的情况,否则除0wa)。
通过x和方向d可以唯一的确定x在这个循环节中的位置。
设$E[i], i in [0, nn)$表示由结点i最终访问成功Y的期望。对期望进行推导
egin{align}
E[0] &= (E[(0+1) \% nn]+1) imes P_1 + (E[(0+2) \% nn] + 2) imes P_2 + cdots (E[(0+m) \% nn] + m) imes P_m
otag \
E[1] &= (E[(1+1) \% nn]+1) imes P_1 + (E[(1+2) \% nn] + 2) imes P_2 + cdots (E[(1+m) \% nn] + m) imes P_m
otag \
&cdots
otag \
E[i] &= (E[(i+1) \% nn]+1) imes P_1 + (E[(i+2) \% nn] + 2) imes P_2 + cdots (E[(i+m) \% nn] + m) imes P_m \
E[i] &= 0, quad if quad id[i]=y
end{align}
这里显然是一个nn元方程组,可以高斯消元解。
这题对精度有限制,因此最开始加入一个bfs,判定x能否走到y,这里一定要判定$P_j, j in [1,m]$是否近似于0。
3. 代码
1 /* 4418 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 //#pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 const int maxn = 220; 45 typedef double mat[maxn][maxn]; 46 47 const double eps = 1e-8; 48 int n, nn, m, x, y, d; 49 int visit[maxn]; 50 int id[maxn]; 51 double P[maxn]; 52 mat g; 53 54 bool gauss_elimination(int n) { 55 int r; 56 57 rep(i, 0, n) { 58 r = i; 59 rep(j, i+1, n) { 60 if (fabs(g[j][i]) > fabs(g[r][i])) 61 r = j; 62 } 63 64 if (r != i) { 65 rep(j, 0, n+1) 66 swap(g[r][j], g[i][j]); 67 } 68 69 if (fabs(g[i][i]) < eps) 70 return false; 71 72 rep(k, i+1, n) { 73 double t = g[k][i] / g[i][i]; 74 rep(j, i+1, n+1) 75 g[k][j] -= t * g[i][j]; 76 } 77 } 78 79 per(i, 0, n) { 80 rep(j, i+1, n) 81 g[i][n] -= g[i][j] * g[j][n]; 82 g[i][n] /= g[i][i]; 83 } 84 85 return true; 86 } 87 88 int bfs(int bx) { 89 queue<int> Q; 90 int p = 0; 91 bool ret = false; 92 93 memset(visit, -1, sizeof(visit)); 94 visit[bx] = p++; 95 Q.push(bx); 96 97 while (!Q.empty()) { 98 int u = Q.front(); 99 Q.pop(); 100 if (id[u] == y) 101 ret = true; 102 rep(j, 1, m+1) { 103 if (fabs(P[j]) < eps) 104 continue; 105 int v = (u + j) % nn; 106 if (visit[v] == -1) { 107 visit[v] = p++; 108 Q.push(v); 109 } 110 } 111 } 112 113 return ret ? p : 0; 114 } 115 116 void solve() { 117 if (x == y) { 118 puts("0.00"); 119 return ; 120 } 121 122 nn = n*2-2; 123 124 rep(i, 0, n) 125 id[i] = i; 126 for (int i=n,j=n-2; i<nn; ++i,--j) 127 id[i] = j; 128 129 int bx; 130 131 if (d == 0) 132 bx = x; 133 else if (d == 1) 134 bx = nn - x; 135 else 136 bx = x; 137 138 int vn = bfs(bx); 139 if (!vn) { 140 puts("Impossible !"); 141 return ; 142 } 143 144 memset(g, 0, sizeof(g)); 145 rep(i, 0, nn) { 146 if (visit[i] == -1) 147 continue; 148 149 int p = visit[i]; 150 g[p][p] = 1; 151 152 if (id[i] == y) 153 continue; 154 155 rep(j, 1, m+1) { 156 int k = visit[(i + j) % nn]; 157 if (k == -1) 158 continue; 159 160 g[p][k] -= P[j]; 161 g[p][vn] += j * P[j]; 162 } 163 } 164 165 bool flag = gauss_elimination(vn); 166 167 if (!flag || fabs(g[0][vn])<eps) { 168 puts("Impossible !"); 169 return ; 170 } 171 172 printf("%.2lf ", g[0][vn]); 173 } 174 175 int main() { 176 ios::sync_with_stdio(false); 177 #ifndef ONLINE_JUDGE 178 freopen("data.in", "r", stdin); 179 freopen("data.out", "w", stdout); 180 #endif 181 182 int t; 183 184 scanf("%d", &t); 185 while (t--) { 186 scanf("%d%d%d%d%d", &n,&m,&y,&x,&d); 187 rep(i, 1, m+1) { 188 scanf("%lf", &P[i]); 189 P[i] /= 100.0; 190 } 191 solve(); 192 } 193 194 #ifndef ONLINE_JUDGE 195 printf("time = %d. ", (int)clock()); 196 #endif 197 198 return 0; 199 }
4. 数据生成器
1 import sys 2 import string 3 from random import randint 4 5 6 def GenData(fileName): 7 with open(fileName, "w") as fout: 8 t = 20 9 for tt in xrange(t): 10 n = randint(1, 100) 11 m = randint(1, 100) 12 y = randint(0, n-1) 13 x = randint(0, n-1) 14 if x==0 or x==n-1: 15 d = -1 16 else: 17 d = randint(0, 1) 18 fout.write("%d %d %d %d %d " % (n, m, y, x, d)) 19 L = [0] * m 20 tot = 0 21 for i in xrange(m-1): 22 x = randint(0, 100-tot) 23 L[i] = x 24 tot += x 25 L[m-1] = 100 - tot 26 fout.write(" ".join(map(str, L)) + " ") 27 28 29 def MovData(srcFileName, desFileName): 30 with open(srcFileName, "r") as fin: 31 lines = fin.readlines() 32 with open(desFileName, "w") as fout: 33 fout.write("".join(lines)) 34 35 36 def CompData(): 37 print "comp" 38 srcFileName = "F:Qt_prjhdojdata.out" 39 desFileName = "F:workspacecpp_hdojdata.out" 40 srcLines = [] 41 desLines = [] 42 with open(srcFileName, "r") as fin: 43 srcLines = fin.readlines() 44 with open(desFileName, "r") as fin: 45 desLines = fin.readlines() 46 n = min(len(srcLines), len(desLines))-1 47 for i in xrange(n): 48 ans2 = int(desLines[i]) 49 ans1 = int(srcLines[i]) 50 if ans1 > ans2: 51 print "%d: wrong" % i 52 53 54 if __name__ == "__main__": 55 srcFileName = "F:Qt_prjhdojdata.in" 56 desFileName = "F:workspacecpp_hdojdata.in" 57 GenData(srcFileName) 58 MovData(srcFileName, desFileName) 59