1. 程式人生 > 其它 >介面測試框架實戰(二)| 介面請求斷言

介面測試框架實戰(二)| 介面請求斷言

(看到題解裡面有一篇和我最初想法挺像但好像不是大眾解法的題解,有點激動,乾脆自己也來寫篇題解好了)

Description

你有 \(n\) 張卡片,每張有一組資料 \(d_i,\ p_i\) 表示貢獻和發動概率,現在你要玩 \(r\) 輪遊戲,每輪編號從 \(1\) 開始:

  • 如果這張卡片在之前被髮動過,直接跳過;

  • 如果當前卡片發動了,產生 \(d_i\) 的貢獻並直接開始下一輪;

  • 否則沒有發動的話,換到下一張卡片。

求期望獲得貢獻。

多測。

\(T \leq 444,\ n \leq 220,\ r \leq 132,\ p_i \in [0,\ 1],\ d_i \in [0,\ 10 ^ 3]\)

Analysis

注意到題目暗含的意思應該是玩多少輪遊戲,就會發動多少次卡片。(具體哪張並不清楚)

根據期望的線性性質,我們可以單獨考慮每個點發動的概率 \(g_i\) ,那麼總貢獻就是 \(\sum g_i \cdot d_i\)

所以在可以不考慮第幾輪的情況下,我們可以這樣設一個 DP 狀態: \(dp_{i,\ j}\) 表示前 \(i\) 張卡片剩下 \(j\) 次沒發動的期望值。

Solution

因為每張卡片發動一次之後就不能再發動了,發動之後的卡片視作概率為 \(1\) ,貢獻為 \(0\) 的“虛卡片”。

假設第 \(j\) 輪發動:

  • 對於之後的輪次,概率為 \(1\)

    ,可以拆成發動 \(+\) 不發動兩種情況;

  • 而對於前面的輪次,概率一致,屬於同類項。

如此來看的話原先定義的 \(g_i\) 實際上可以變成另一種定義:\(i\) 張卡片至少發動一次的概率

會不會算重呢?假如如果第 \(j\) 輪前面還有發動的輪次 \(k\) ,這種情況就換合併到第一次在第 \(k\) 輪發動的,前面有多個同理,不會的。

那就有 \(g_1 = 1 - (1 - p_1) ^ r\) ,如果另加前 \(j\) 輪就把 \(r\) 改成 \(j\) 就好了。

問題解決了一半。

還有一個問題,我們還是被每輪只能發動一次這個條件限制的死死的:因為前者的發動概率會直接影響

後面的卡片發動概率,所以同時要算當前狀態的概率以及期望。

我們就可以理解為每張卡片在它後面的每張卡片上疊了 buff 。

(不知道怎麼的)猛然間想起期望入門的時候做過的這道題

前者影響後者,那就正難則反!!全部逆推,反正後面的卡片都要被前面影響,該疊 buff 就正常疊就行了。

所以就有很自然的 DP 方程式啦(注意是逆推啦):

\[dp_{i,\ j} = dp_{i + 1,\ j} \cdot (1 - p_i) ^ j + dp_{i + 1,\ j - 1} \cdot (1 - (1 - p_i) ^ j) \]

分別的兩個係數就是上文講的發動或者不發動。

(常熟還小/hanx)

Code

Code

/*

*/
#include 
using namespace std;
typedef long long ll;
const int N = 222;
int n, r, d[N];
double p[N], f[N][N];
inline int read() {
	char ch = getchar();
	int s = 0, w = 1;
	while (!isdigit(ch)) {if (ch == '-') w = -1; ch = getchar();}
	while (isdigit(ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar();}
	return s * w;
}
inline double dead() {
	char ch = getchar();
	ll s = 0, w = 1, k = 0;
	double m = 1; bool is = 0;
	while (!isdigit(ch)) {if (ch == '-') w = -1; ch = getchar();}
	while (isdigit(ch) || ch == '.') {
		if (ch == '.') is = 1;
		else if (!is) s = (s << 3) + (s << 1) + (ch ^ 48);
		else k = (k << 3) + (k << 1) + (ch ^ 48), m *= 0.1;
		ch = getchar();
	}
	return (m * k + s) * w;
}
inline void mian() {
	memset(f, 0, sizeof(f));
	n = read(); r = read();
	for (int i = 1; i <= n; ++i) p[i] = dead(), d[i] = read();
	for (int i = n; i >= 1; --i) {
		double P = 1.0 - p[i];
		for (int j = 1; j <= r; ++j) {
			f[i][j] = f[i + 1][j] * P + (f[i + 1][j - 1] + d[i]) * (1.0 - P);
			P *= 1.0 - p[i];
		}
	}
	printf("%.9lf\n", f[1][r]);
}
int main() {
	int T = read();
	while (T--) mian();
	return 0;
}