可以
2026-04-19 16:16:54
发布于:河南
12阅读
0回复
0点赞
#include <bits/stdc++.h>
using namespace std;
const double PI = acos(-1);
const double EPS = 1e-9;
typedef complex<double> cd;
const int MAXN = 1 << 19; // 2^19 = 524288 > 200000*20
cd A[MAXN], B[MAXN];
int rev[MAXN];
void init_fft(int n) {
int bit = 0;
while ((1 << bit) < n) bit++;
for (int i = 0; i < n; i++) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
}
}
void fft(cd *a, int n, int inv) {
for (int i = 0; i < n; i++) {
if (i < rev[i]) swap(a[i], a[rev[i]]);
}
for (int len = 2; len <= n; len <<= 1) {
double ang = 2 * PI / len * (inv ? -1 : 1);
cd wn(cos(ang), sin(ang));
for (int i = 0; i < n; i += len) {
cd w(1);
for (int j = 0; j < len / 2; j++) {
cd u = a[i + j], v = a[i + j + len / 2] * w;
a[i + j] = u + v;
a[i + j + len / 2] = u - v;
w *= wn;
}
}
}
if (inv) {
for (int i = 0; i < n; i++) a[i] /= n;
}
}
vector<double> poly_pow(vector<double> p, int y) {
int n = 1;
int max_sum = p.size() - 1;
while (n <= max_sum * y) n <<= 1;
init_fft(n);
for (int i = 0; i < n; i++) A[i] = cd(0, 0);
for (int i = 0; i <= max_sum; i++) A[i] = cd(p[i], 0);
// 快速幂:log(y) 次 FFT
for (int i = 0; i < n; i++) B[i] = cd(1, 0);
int exp = y;
while (exp > 0) {
if (exp & 1) {
fft(A, n, 0);
fft(B, n, 0);
for (int i = 0; i < n; i++) B[i] *= A[i];
fft(B, n, 1);
fft(A, n, 1);
// 恢复 A
for (int i = 0; i < n; i++) A[i] = cd(p[i % (max_sum+1)], 0);
}
fft(A, n, 0);
for (int i = 0; i < n; i++) A[i] *= A[i];
fft(A, n, 1);
exp >>= 1;
}
vector<double> res(n);
for (int i = 0; i < n; i++) res[i] = B[i].real();
return res;
}
// 标准正态分布累积分布函数(使用误差函数,更精确)
double phi(double x) {
return 0.5 * (1 + erf(x / sqrt(2)));
}
void solve() {
int X, Y;
cin >> X >> Y;
// 大数据:中心极限定理
if (Y > 800) {
double mu = (X - 1) / 2.0;
double var = (X * X - 1) / 12.0;
double E = Y * mu;
double sigma = sqrt(Y * var);
for (int i = 0; i < 10; i++) {
int A, B;
cin >> A >> B;
// 连续性校正
double L = (A - 0.5 - E) / sigma;
double R = (B + 0.5 - E) / sigma;
double ans = phi(R) - phi(L);
printf("%.6lf\n", ans);
}
}
// 小数据:FFT 精确计算
else {
// 单个骰子的概率分布
vector<double> prob(X, 1.0 / X);
// 计算 Y 次卷积
vector<double> res = prob;
for (int i = 2; i <= Y; i++) {
vector<double> tmp(res.size() + X - 1, 0);
for (int j = 0; j < res.size(); j++) {
for (int k = 0; k < X; k++) {
tmp[j + k] += res[j] * prob[k];
}
}
res = tmp;
}
// 前缀和以便快速查询区间概率
vector<double> prefix(res.size() + 1, 0);
for (int i = 0; i < res.size(); i++) {
prefix[i+1] = prefix[i] + res[i];
}
for (int i = 0; i < 10; i++) {
int A, B;
cin >> A >> B;
// 注意:伤害范围是 [A, B],需要累加概率
double ans = prefix[min(B, (int)res.size()-1) + 1] - prefix[A];
printf("%.6lf\n", ans);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
全部评论 1
vfv
1周前 来自 浙江
0












有帮助,赞一个