题解:P16044 [ICPC 2022 NAC] Double Sort
lailai0916 · · 题解
题意简述
从
解题思路
设排序后的原序列为
每个
将差分排序为
其中
令
预处理:
交换
当
交错求和会严重损失浮点精度。代码用大整数精确计算正项和与负项和,仅在最后做一次除法。组合数按相邻两项递推。总计需要
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using ull=unsigned long long;
using ui=unsigned int;
using u128=unsigned __int128;
using ld=long double;
const int N=55;
const int M=10005;
const ull base=1000000000;
struct big
{
vector<ui> a;
big(ull x=0)
{
while(x)
{
a.push_back(x%base);
x/=base;
}
}
void trim()
{
while(!a.empty()&&a.back()==0)a.pop_back();
}
big &operator+=(const big &x)
{
int n=a.size(),m=x.a.size();
if(n<m)
{
a.resize(m);
n=m;
}
ull cur=0;
for(int i=0;i<n;i++)
{
cur+=a[i]+(i<m?x.a[i]:0);
a[i]=cur%base;
cur/=base;
}
if(cur)a.push_back(cur);
return *this;
}
big &operator-=(const big &x)
{
int n=a.size(),m=x.a.size();
ll cur=0;
for(int i=0;i<n;i++)
{
cur=(ll)a[i]-(i<m?x.a[i]:0)-cur;
if(cur<0)
{
cur+=base;
a[i]=cur;
cur=1;
}
else
{
a[i]=cur;
cur=0;
}
}
trim();
return *this;
}
void mul(ull x)
{
u128 cur=0;
for(auto &v:a)
{
cur+=(u128)v*x;
v=cur%base;
cur/=base;
}
while(cur)
{
a.push_back(cur%base);
cur/=base;
}
}
void div(ui x)
{
int n=a.size();
ull cur=0;
for(int i=n-1;i>=0;i--)
{
cur=cur*base+a[i];
a[i]=cur/x;
cur%=x;
}
trim();
}
ld val()const
{
int n=a.size();
ld res=0;
for(int i=n-1;i>=0;i--)res=res*base+a[i];
return res;
}
};
ull c[N][N];
big comb[M],sum[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i=0;i<=n;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)c[i][j]=c[i-1][j-1]+c[i-1][j];
}
comb[n]=big(1);
for(int i=n+1;i<=m;i++)
{
comb[i]=comb[i-1];
comb[i].mul(i);
comb[i].div(i-n);
}
for(int i=1;i<=n;i++)
{
for(int j=m;j>=n;j-=i)sum[i]+=comb[j];
}
cout<<fixed<<setprecision(10);
for(int i=1;i<=n;i++)
{
int k=n-i;
big pos,neg;
if(k==0)
{
pos=sum[1];
pos.mul(n);
}
else
{
for(int j=k+1;j<=n;j++)
{
big cur=sum[j];
cur.mul(c[j-2][k-1]);
cur.mul(c[n][j]);
if((j-k-1)&1)neg+=cur;
else pos+=cur;
}
}
pos-=neg;
cout<<pos.val()/comb[m].val()<<'\n';
}
return 0;
}