题目来源:https://codeforces.com/gym/101522/problem/E
★这题就是一道模拟,难度不大,但是我题目看不懂,很难受awa~
翻译:
有2*n个盒子,标号为1到n,每个标号标记盒子2次。盒子的标号是不可见的(除非操作的时候取出),现在有r轮操作,每次从2n个箱子里任意取2个盒子,如果盒子标号相同,那么这轮得分即为标号;否则为0 。已经进行了r-1次操作,现在想让这最后一次操作的得分最大,求这个最大的期望
思路:
可以分4种情况讨论:
①:保守的情况,在这r-1次操作中的最大得分 可能就是最大期望,记为tmp
②:如果想比保守的情况大,那当然在 tmp+1 到n里面找,如果这里面已经有出现过两次的标记,那肯定是比①大的
③:然后就是只出现过一次的标记,(也是在tmp+1到n里面找,下面也一样,原因不用说吧 ),cnt为没有开过的箱子的数目,那匹配成功的概率是 1.0/cnt (表格里面的 i 不严谨,大家心里明白就好)
tmp | i |
---|---|
1-(1.0/cnt) | 1.0/cnt |
④:如果有很大的数一次都没出现,那么只能 摸鱼 了,高中数学中排列组合: 概率= 2.0/(cnt*(cnt-1)
tmp | i | i+1 |
---|---|---|
1-tot | 2.0/(cnt*(cnt-1) | 2.0/(cnt*(cnt-1) |
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
const int maxn=2e5+5;
const int sz=1<<6;
const int mod=1e9+7;
const int inf=2e9+7;
typedef long long LL;
int n,m;
int num[maxn];
bool vis[maxn];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
while(~scanf("%d%d",&n,&m)){
memset(num,0,sizeof num);
memset(vis,0,sizeof vis);
LL cnt=2*n;
int tmp=0;
while(--m){
int p1,p2,n1,n2;
scanf("%d%d%d%d",&p1,&p2,&n1,&n2);
if(!vis[p1]){
vis[p1]=1;
num[n1]++;
cnt--;
}
if(!vis[p2]){
vis[p2]=1;
num[n2]++;
cnt--;
}
if(n1==n2) tmp=max(tmp,n1);
}
double ans=0,sum=0,tt=cnt*(cnt-1)*1.0/2,tot=0;
for(int i=tmp+1;i<=n;i++){
if(num[i]==2){
ans=max(tmp,i);
}
}
for(int i=tmp+1;i<=n;i++){
if(num[i]==1){
ans=max(ans,i*1.0/cnt+tmp*1.0*(1-1.0/cnt));
}
}
for(int i=tmp+1;i<=n;i++){
if(num[i]==0&&i!=tmp){
tot+=1.0/tt;
sum+=i*1.0/tt;
}
}
sum+=(1-tot)*tmp;
printf("%.6lf\n",max(ans,sum));
}
return 0;
}