https://codeforces.ml/gym/103373
C. A Sorting Problem
开始手动模拟了下过程,发现了关于下标的规律,假设第5个位置上是1,我们要把5移动到第五个位置,5的下标会变成1的下标,1到4的下标会变成2到5原来的下标。于是开始观察记录下标的数组。想了很久都没想到的怎么维护这个过程。
后来发现其实不用维护这个过程,我们最后的目的就是把下标一一对应就好,那么其实就是算把数组变成上升数组要移动多少次,这个也就是求逆序对,
所以用线段树求个逆序对就得到答案了。
int a[maxn],b[maxn];
int t[maxn<<4];
void update(int rt,int l,int r,int p)
{
if(l==r)
{
t[rt]=1;
return;
}
int mid=(l+r)>>1;
if(mid>=p)
update(lson,l,mid,p);
else
update(rson,mid+1,r,p);
t[rt]=t[lson]+t[rson];
}
int query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return t[rt];
}
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)
ans+=query(lson,l,mid,L,R);
if(R>mid)
ans+=query(rson,mid+1,r,L,R);
return ans;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[a[i]]=i;
}
ll ans=0;
//print1;
for(int i=n;i>=1;i--)
{
ans+=query(1,1,n,1,b[i]);
update(1,1,n,b[i]);
}
printf("%lld\n",ans);
}
D. Drunk Passenger
同样也是手动模拟了下,发现了一些规律:
假设有九个人,如果第一个人坐在了第八个位置,从2到7这些位置一定是2到7这些人,那么我们只需要知道在剩下的两个位置中的第九个位置被占据的概率,再乘上坐第八个位置的概率就是当前情况的期望贡献了;如果第一个人坐在了第七个位置,那么只需要知道剩余三个位置里面第九个位置被占据的概率。后面的位置也同理,最后我们只需要把这些位置的贡献相加就是要求的了。
所以我们可以令dp[i]表示在i个位置里面某个固定位置被其他(i-1)个人占据的概率,我们从1开始递推到300就好了,再根据上述方法就贡献
其实打表发现dp数组每个值都是0.5(一开始打完表发现全是0.5还以为打错了,改了下写法wa了蛮多发),应该可以通过这个来推公式
double dp[maxn];
int main()
{
dp[1]=1.0;
for(int i=2;i<=300;i++)
{
double tem=1.0/i;
for(int j=1;j<i;j++)
{
dp[i]+=tem*dp[j];
}
//printf("%f\n",dp[i]);
}
int n;
scanf("%d",&n);
double ans=0;
for(int i=n-1;i>=1;i--)
{
ans+=dp[i]*1.0*1.0/(n-1);
//printf("%f\n",dp[i]);
}
printf("%.10f\n",ans);
}