原题题面
Generate three integers a, b, and c in
[
1
,
n
]
[1,n]
[1,n] with equal probability independently, and use them as the three right-angle side length of a right-angled tetrahedron. Find the expectation of the reciprocal square of the distance from the right-angle apex to the slope (Euclidean distance).
For each test case, output a line containing the answer mod 998244353.
输入格式
In the first line, you should read an integer T denoting the number of test cases.
In every test case, the only line will include an integer n.
It is guaranteed that T is no larger than
2
×
1
0
6
2×10^6
2×106 and n is no larger than
6
×
1
0
6
6×10^6
6×106.
输出格式
For each test case, output the only line containing just one integer denoting the answer mod 998244353.
输入样例
3
1
2
3
输出样例
3
124780546
194103070
题面分析
给定n,在[1,n]中等概率随机选出3个数
a
,
b
,
c
a,b,c
a,b,c(可以重复),做直角四面体(a,b,c三遍两两垂直),记顶点到底面的距离为
h
h
h求,期望
E
(
1
h
2
)
E(\frac{1}{h^2})
E(h21)。
直接考虑
n
≥
3
n\geq3
n≥3的情况。
首先要做的自然就是求出
h
h
h。
把
a
,
b
,
c
a,b,c
a,b,c看作三个坐标轴,顶点看作原点后即可建系。
设平面为
x
+
A
y
+
B
z
=
C
x+Ay+Bz=C
x+Ay+Bz=C,代入
(
a
,
0
,
0
)
,
(
0
,
b
,
0
)
,
(
0
,
0
,
c
)
(a,0,0),(0,b,0),(0,0,c)
(a,0,0),(0,b,0),(0,0,c)后得到平面为
x
+
a
b
y
+
a
c
z
=
a
x+\frac{a}{b}y+\frac{a}{c}z=a
x+bay+caz=a
那
(
0
,
0
,
0
)
(0,0,0)
(0,0,0)到该平面距离为
h
=
∣
a
∣
1
2
+
(
a
b
)
2
+
(
a
c
)
2
h=\frac{|a|}{\sqrt{1^2+(\frac{a}{b})^2+(\frac{a}{c})^2}}
h=12+(ba)2+(ca)2∣a∣
=
1
1
a
2
+
1
b
2
+
1
c
2
=\sqrt{\frac{1}{\frac{1}{a^2}+\frac{1}{b^2}+\frac{1}{c^2}}}
=a21+b21+c211
那么
1
h
2
=
1
a
2
+
1
b
2
+
1
c
2
\frac{1}{h^2}=\frac{1}{a^2}+\frac{1}{b^2}+\frac{1}{c^2}
h21=a21+b21+c21
然后我们可以计算发现,对于在
[
1
,
n
]
[1,n]
[1,n]等概率选取的
a
,
b
,
c
a,b,c
a,b,c的所有方案中。
n
n
n个数字出现的次数是相等的,都是
n
2
n^{2}
n2(
a
a
a确定后,
b
,
c
b,c
b,c各有
n
n
n种选法)。
所以最后的答案
E
(
1
h
2
)
=
3
n
2
∑
i
=
1
n
1
i
2
n
3
=
3
∑
i
=
1
n
1
i
2
n
E(\frac{1}{h^2})=\frac{3n^{2}\sum_{i=1}^{n}\frac{1}{i^2}}{n^3}=\frac{3\sum_{i=1}^{n}\frac{1}{i^2}}{n}
E(h21)=n33n2∑i=1ni21=n3∑i=1ni21
AC代码(1968ms)
#include <bits/stdc++.h>
using namespace std;
const long long mod=998244353;
const long long MAXN=6e6;
long long factor[MAXN+10];//阶乘
long long invFactor[MAXN+10];//阶乘逆元
long long invn[MAXN+10];//逆元
long long answer[MAXN+10];//答案
inline long long quick_pow(long long a, long long b)
{
long long ans=1, base=a;
while(b!=0)
{
if (b&1)
ans=(long long) ans*base%mod;
base=(long long) base*base%mod;
b>>=1;
}
return ans;
}
inline void init()//预处理
{
factor[0]=invFactor[0]=invn[0]=factor[1]=invFactor[1]=invn[1]=1;
for(int i=2; i<=MAXN; i++)
{
factor[i]=factor[i-1]*i%mod;
invn[i]=(long long) (mod-mod/i)*invn[mod%i]%mod;
invFactor[i]=invFactor[i-1]*invn[i]%mod;
}
}
inline void init2()//预处理答案
{
long long sum=0;
for(long long i=1; i<=MAXN; i++)
{
long long ans=1;
sum=(sum+(long long)invn[i]*invn[i]%mod)%mod;
ans=(long long) sum*3%mod*invn[i]%mod;
answer[i]=ans;
}
}
void solve()
{
// printf("%lld\n",205*quick_pow(192,mod-2)%mod);
init();
init2();
int t;
scanf("%d", &t);
while(t--)
{
long long n;
scanf("%lld", &n);
if(n==1)
{
printf("3\n");
continue;
}
if(n==2)
{
printf("124780546\n");
continue;
}
printf("%lld\n", answer[n]);
}
}
int main()
{
// ios_base::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long long test_index_for_debug=1;
char acm_local_for_debug;
while(cin>>acm_local_for_debug)
{
cin.putback(acm_local_for_debug);
if (test_index_for_debug>100)
{
throw runtime_error("Check the stdin!!!");
}
auto start_clock_for_debug=clock();
solve();
auto end_clock_for_debug=clock();
cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;
cerr<<"Test "<<test_index_for_debug++<<" Run Time: "
<<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;
cout<<"--------------------------------------------------"<<endl;
}
#else
solve();
#endif
return 0;
}
后记
可以叉积,可以海伦公式,能搞的方法很多,只要老老实实算就能出答案。
DrGilbert 2020.8.4