列队春游
列队春游
题目描述
输入格式
输出格式
样例
CODE
1.dfs TLE 20%
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 302; const int maxm = 9e4 + 10; int n, h[maxn], b[maxn]; ll sum=1, ans; bool v[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } ll check() { ll ans = 0; /*for(int i=1; i<=n; i++) { printf("%d ", b[i]); } printf("\n");*/ for(int i=n; i>=1; i--) { int can = i; while(can--) { ans++; if(b[i] <= b[can]) break; //printf("b[%d]=%d b[%d]=%d\n", i, b[i], can, b[can]); } } //printf("ans == %lld\n", ans); return ans; } ll dfs(int now, int n) { ll ans = 0; if(now > n) { return check(); } for(int i=1; i<=n; i++) { if(v[i]) continue; v[i] = 1; b[now] = h[i]; ans += dfs(now+1, n); v[i] = 0; } return ans; } int main() { n = read(); for(int i=1; i<=n; i++) { h[i] = read(); } for(int i=2; i<=n; i++) { sum *= i; } ans = dfs(1, n); printf("%.2lf", (double)ans/sum); return 0; }
2.正解
假设比i矮的有s个,称为s集合,对于j属于s,设f[i]为前面期望比i矮的个数,d[j]是j对i的贡献(在个数上),p[j]是j对i有贡献的概率。
d[i] = 1 * p[j], f[i] = sigma d[j](j属于s) , p[j] = (j对i有贡献的排列数)/(n个学生的排列总数)= (n-s)!*A(n, s-1) / n! = 1 / (n-s+1)
//详细解释:摘抄自MaxMercer的博客
我们先忽略掉除s集合里j之外的s-1个人. 此时我们算出j刚好在i前面一位的排列数. 怎么算呢? 现在删去s-1个人, 还剩n-s+1个人. 因为j在刚好前一位, 所以我们假设j和i是一个人, 那么对剩下n-s个人(j和i合并), 随意乱排列的排列数是 (n-s)!. 因为j和i我们看做一个人, 那么此时(n-s)!可以看做n-s+1个人j在i刚好前一位的所有排列数. 然后我们再把删去的s集合里的s-1个人插进这个排列里. 这样j和i之间的人就肯定是s集合里的了. 把s-1个人插回去的排列数是(n-s)! * n! / (n - s + 1)! , 即(n-s)! * A(n, s-1). 那么p[j] = (n-s)! * A(n, s-1) / n!. 简化而得p[j] = 1 / (n - s + 1).
//摘抄自bfk的博客
要满足j对i有贡献,那么j与i之间只能有其他属于s集合的学生,有s-1个。
先忽略这s-1个学生,现在还剩n-s+1个学生。那么这些学生的排列中,j刚好在i前一个的排列有: (n-s)! 个
而剩下(s-1)个比i矮的学生的分散在上述排列中的排列有
(n-s)!* A(n,s-1)
=( (n-s)!* n! ) / (n-s+1)!
=n!/(n-s+1)
只有在这些排列中,i与j之间都不会出现比i高或和i一样高的,即j对i有贡献。
p[j]
=(n!/(n-s+1))/ n!
=1/( n-s+1)
f[i] = s * p[j] = s / (n-s+1), 视野 = f[i] + 1,num[x]个人的期望视野就是num[x] * (f[i] + 1)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 302; const int maxm = 9e4 + 10; int n, num[1005], x, s; double ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { scanf("%d", &n); for(int i=1; i<=n; i++) { scanf("%d", &x); num[x]++; } for(int i=1; i<=1000; i++) { if(num[i]) { ans += (double)(num[i]*s)/(n-s+1) + (double)(num[i]); } s += num[i]; } printf("%.2lf", ans); return 0; }