题解 CF303E 【Random Ranking】
来自大常数的愤怒
首先我们思考一个简单的情况,如果所有的
很显然,每个人在得到每个排名的概率都是
那么再考虑一种稍微难一点的情况:假设
此时不难发现,第一个人的排名可能是
想到这些,我们就有一个思路:
首先,我们可以把所有的
接着,我们对于每个人,枚举他得分所在的区间
算出来这个数之后,就可以向对应的答案
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
int l[110],r[110];
double pless(int i,int x)
{
if(x<l[i])return 0;
if(x>r[i])return 1;
return (double)(x-l[i])/(r[i]-l[i]);
}
double pmore(int i,int x)
{
return 1-pless(i,x);
}
double p(int i,int L,int R)
{
return pless(i,R)-pless(i,L);
}
double ans[110][110];
int pos[210];
double f[110][110];
double g[110][110];
void work(int x,int v)
{
for(int i=0;i<=n;i++)
for(int j=0;i+j<=n;j++)
f[i][j]=0;
f[0][0]=1;
for(int t=1;t<=n;t++)
{
if(t==x)continue;
for(int i=0;i<t;i++)
for(int j=0;i+j<t;j++)
{
g[i][j]+=f[i][j]*pmore(t,pos[v+1]);
g[i][j+1]+=f[i][j]*p(t,pos[v],pos[v+1]);
g[i+1][j]+=f[i][j]*pless(t,pos[v]);
}
for(int i=0;i<=t;i++)
for(int j=0;i+j<=t;j++)
{
f[i][j]=g[i][j];
g[i][j]=0;
}
}
for(int i=0;i<n;i++)
for(int j=0;i+j<n;j++)
for(int k=1;k<=j+1;k++)
ans[x][i+k]+=f[i][j]*p(x,pos[v],pos[v+1])/(j+1);
return ;
}
int main()
{
scanf("%d",&n);int N=0;
for(int i=1;i<=n;i++)
{
scanf("%d %d",&l[i],&r[i]);
pos[++N]=l[i];pos[++N]=r[i];
}
sort(pos+1,pos+N+1);
N=unique(pos+1,pos+N+1)-pos-1;
for(int i=1;i<=n;i++)
for(int j=1;j<N;j++)
work(i,j);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
printf("%.10lf%c",ans[i][j],j==n?'\n':' ');
return 0;
}
然后这份代码由于常数过大光荣TLE:提交记录
这份代码中有两部分总复杂度是
第一个很好处理,我们只需要对每个人记
但是第二个就不是那么显然了
如果你是大佬那当我没说
虽然我也没想多久
我们首先考虑在外层枚举钦定的区间,这一部分是
我们发现我们需要处理这样一个东西:对于每个人,求出对除了他以外的人做背包之后得到的结果。
这个东西我们可以考虑分治:假设我们正在处理一个区间
这样分析一下复杂度:向背包中加入一个人是
然后就可以开始卡常了:
第一个提交:光荣TLE
第二个提交:将很多除法预处理,成功AC
第三个提交:加了一点剪枝,跑得更快
最终代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
double eps=1e-8;
int n;
int l[110],r[110];
double pl[110][210];
double pm[110][210];
double pv[110][210];
inline double pless(int i,int x)
{
if(x<l[i])return 0.0;
if(x>r[i])return 1.0;
return (double)(x-l[i])/(r[i]-l[i]);
}
inline double pmore(int i,int x)
{
return 1.0-pless(i,x);
}
inline double p(int i,int L,int R)
{
return pless(i,R)-pless(i,L);
}
double ans[110][110];
int pos[210];
double sum[110][110][110];
double f[10][110][110];
double g[110][110];
int s[10];
int work_cnt;
void work(int o,int x,int v)
{
work_cnt+=s[o]*(s[o]-1)/2;
for(register int i=0;i<=s[o];++i)
for(register int j=0;i+j<=s[o];++j)
{
if(f[o][i][j]<eps)continue;
g[i][j]+=f[o][i][j]*pm[x][v+1];
g[i+1][j]+=f[o][i][j]*pl[x][v];
g[i][j+1]+=f[o][i][j]*pv[x][v];
}
s[o]++;
for(register int i=0;i<=s[o];++i)
for(register int j=0;i+j<=s[o];++j)
{
f[o][i][j]=g[i][j];
g[i][j]=0.0;
}
return ;
}
//int solve_cnt;
void solve(int d,int L,int R,int v)
{
// solve_cnt++;
if(L==R){
for(register int i=0;i<=s[d];++i)
for(register int j=0;i+j<=s[d];++j)
sum[L][i][j]+=f[d][i][j]*pv[L][v];
return ;
}
int mid=(L+R)>>1;
s[d+1]=s[d];
for(register int i=0;i<=s[d];++i)
for(register int j=0;i+j<=s[d];++j)
f[d+1][i][j]=f[d][i][j];
for(register int i=L;i<=mid;++i)
work(d+1,i,v);
solve(d+1,mid+1,R,v);
s[d+1]=s[d];
for(register int i=0;i<=s[d];++i)
for(register int j=0;i+j<=s[d];++j)
f[d+1][i][j]=f[d][i][j];
for(register int i=mid+1;i<=R;++i)
work(d+1,i,v);
solve(d+1,L,mid,v);
return ;
}
int main()
{
scanf("%d",&n);int N=0;
for(register int i=1;i<=n;++i)
{
scanf("%d %d",&l[i],&r[i]);
pos[++N]=l[i];pos[++N]=r[i];
}
sort(pos+1,pos+N+1);
N=unique(pos+1,pos+N+1)-pos-1;
for(int i=1;i<=n;++i)
for(int j=1;j<=N;++j)
{
pm[i][j]=pmore(i,pos[j]);
pl[i][j]=pless(i,pos[j]);
if(j<N)pv[i][j]=p(i,pos[j],pos[j+1]);
}
f[0][0][0]=1.0;s[0]=0;
for(register int i=1;i<N;++i)
{
// work_cnt=0;
// solve_cnt=0;
solve(0,1,n,i);
// if(i%10==0){
// cerr<<i<<"\n";
// cerr<<"work_cnt="<<work_cnt<<"\n";
// cerr<<"solve_cnt="<<solve_cnt<<"\n";
// }
}
for(register int x=1;x<=n;++x)
for(register int i=0;i<n;++i)
for(register int j=0;i+j<n;++j)
for(register int k=1;k<=j+1;++k)
ans[x][i+k]+=sum[x][i][j]/(j+1);
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
printf("%.10lf%c",ans[i][j],j==n?'\n':' ');
// cerr<<"N="<<N<<"\n";
// cerr<<work_cnt<<"\n";
return 0;
}