大体题意:给一个N个点的凸包,求任选K点组成的子凸包的面积期望怎么做(3≤k≤n≤2500)
尝试的挣扎:
1.暴力枚举?显然超时。
2.考虑新加入一个点对期望的贡献?不会计算。
GG
正经题解:
被rqy秒了......
#include <bits/stdc++.h>
#define ll long long
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define pii pair<int,int>
#define pdd pair<double,double>
#define all(x) (x).begin(),(x).end()
#define mp make_pair
#define pb push_back
#define ls (o<<1)
#define rs (o<<1|1)
#define mid (l+r>>1)
using namespace std;
const int N = 3000;
long double dp[N][N]; //精度需要用long double
long double C(int n,int m) {
if(m>n) return 0;
if(n<0||m<0) return 0;
return dp[n+1][m+1];
}
pdd s[N];
double cs(int i,int j) { //这里在叉积里直接取了负数
return -(s[i].first*s[j].second-s[i].second*s[j].first);
}
int n,k;
int main() {
int T;
dp[0][0] = 1;
rep(i, 1, 2501)
rep(j, 1, i)
dp[i][j] = dp[i-1][j-1]+dp[i-1][j];
cin>>n>>k;
rep(i, 1, n) cin>>s[i].first>>s[i].second; //顺时针给点
double ans = 0;
rep(i, 1, n) {
rep(j, i+1, n) {
if(i==j) continue;
int num = abs(max(j,i)-min(j,i)+1);
ans += cs(i,j)*C(n-num,k-2)/C(n,k); //---ij----相邻
ans += cs(j,i)*C(num-2,k-2)/C(n,k); //---ji----相邻
}
}
printf("%.10f",ans/2);
return 0;
}