Problem:
Problem K: Collector
※この物語はフィクションであり、実在の人物、団体などとは一切関係がありません。
最近ソーシャルゲームがとても人気で、
たくさんの会社がソーシャルゲームを開発しています。
あなたは競合しているソーシャルゲーム開発会社の一つにスパイとして潜入しています。
問題
あなたの務めている会社では、ソーシャルゲームを開発している。
開発しているゲームは、カードを集めて戦うゲームであり、
1回300円
の有料”ガチャガチャ”を収益の柱にしている。
このゲームのカードには、”ノーマル”、”レア”、”Sレア”の3種類がある。”Sレア”カードはN種類存在する。
有料”ガチャガチャ”では、1回行うごとに97％の確率で1枚のレアカードが手に入り、3%の確率で1枚のSレアカードが手に入る。
有料”ガチャガチャ”における各Sレアカードの出現割合(合計3%)を操作する権限を持っているあなたは、
会社の利益を「減少」させることにした。
まず、様々なプレイヤーの有料”ガチャガチャ”の利用傾向を調べたところ、 「各プレイヤーは、
各々の好きなSレアカードを引くと、 満足し、その後は”ガチャガチャ”の利用を行わない」ということが明らかになった。 以上の情報より、
あなたは ”各プレイヤーは、特定のSレアカードを好み、そのSレアカードを引くまでガチャガチャをし続ける”
という仮定の下で会社の利益をモデル化した。
すなわち会社の利益とは、 Sレアカードiを好む人の割合 ×
Sレアカードiが得られるまでの消費金額の期待値 の総和である。
Sレアカードの出現割合を適切に操作することで、 会社の利益を「最小化」せよ。
ただし、出現割合は以下の条件を満たさなければならない。
Sレアカード全体の出現割合の和は3%である
各Sレアカードの出現割合は最低0.01%である
入力
N (Sレアカードの種類)
P_1 (カード1が好きな人の割合)
P_2 (カード2が好きな人の割合)
...
P_N (カードNが好きな人の割合)
出力
問題文で定義された会社の利益の最小値を出力せよ。
制約
\( N \)は整数
\( 1 \leq N \leq 300 \)
\( 0.0 \leq P_i (1 \leq i \leq N) \leq 1.0 \)
\( P_1 + P_2 + \cdots + P_N = 1.0 \)
\( P_i \)は小数点以下5桁まで与えられる
誤差は相対\( 10 ^ {-6} \) まで許容される
入出力例
入力1
1
1.00000
出力1
10000
入力2
2
0.00001
0.99999
出力2
10063.3444816
カード1は\( 0.01% \)の割合で出現し、カード2は\( 2.99% \)の割合で出現するように設定する。
入力3
2
0.50000
0.50000
出力3
20000.0000000

Submitted solutions:

code_snippet: #include <cmath>
#include <iomanip>
#include <iostream>
using namespace std;
const double lim = 0.0001;
int n; double p[309], sq[309], a[309];
int main() {
	cin >> n;
	for (int i = 0; i < n; i++) cin >> p[i], sq[i] = sqrt(p[i]), a[i] = 0.03 / n;
	double ret = 1.0e+9; int cnt = 0;
	while (true) {
		double curval = 0.0;
		for (int i = 0; i < n; i++) curval += p[i] / a[i];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < i; j++) {
				double sa = a[i] + a[j], sp = sq[i] + sq[j];
				a[i] = sq[i] / sp * sa;
				a[j] = sq[j] / sp * sa;
				if (a[i] < lim) a[j] -= lim - a[i], a[i] = lim;
				if (a[j] < lim) a[i] -= lim - a[j], a[j] = lim;
			}
		}
		ret = 0.0;
		for (int i = 0; i < n; i++) ret += p[i] / a[i];
		if (abs(curval - ret) < 1.0e-8) break;
		cnt++;
	}
	cout << fixed << setprecision(15) << 300 * ret << endl;
	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3292
final_rank: 1

code_snippet: #include <cmath>
#include <iomanip>
#include <iostream>
using namespace std;
const double lim = 0.0001;
int n; double p[309], a[309];
int main() {
	cin >> n;
	for (int i = 0; i < n; i++) cin >> p[i], a[i] = 0.03 / n;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < i; j++) {
			double sa = a[i] + a[j], l = lim, r = sa - lim;
			for (int k = 0; k < 45; k++) {
				double m = (l + r) * 0.5;
				if (p[i] * pow(m, -2.0) > p[j] * pow(sa - m, -2.0)) l = m;
				else r = m;
			}
			a[i] = l, a[j] = sa - l;
		}
	}
	double ret = 0.0;
	for (int i = 0; i < n; i++) ret += p[i] / a[i];
	cout << fixed << setprecision(15) << 300 * ret << endl;
	return 0;
}
accuracy: 0.02912621359223301
time_ms: 30
memory_kb: 3540
final_rank: 3

code_snippet: #include <cmath>
#include <iomanip>
#include <iostream>
using namespace std;
const double lim = 0.0001;
int n; double p[309], a[309];
int main() {
	cin >> n;
	for (int i = 0; i < n; i++) cin >> p[i], a[i] = 0.03 / n;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < i; j++) {
			double sa = a[i] + a[j], l = lim, r = sa - lim;
			for (int k = 0; k < 45; k++) {
				double m = (l + r) * 0.5;
				if (p[i] * log(m) < p[j] * log(sa - m)) l = m;
				else r = m;
			}
			a[i] = l, a[j] = sa - l;
		}
	}
	double ret = 0.0;
	for (int i = 0; i < n; i++) ret += p[i] / a[i];
	cout << fixed << setprecision(15) << 300 * ret << endl;
	return 0;
}
accuracy: 0.02912621359223301
time_ms: 10
memory_kb: 3464
final_rank: 2