题解:
n
!
n!
n!个排列可以看做
n
!
n!
n!个
n
n
n维点,那么序列
x
x
x可以被构造出来当且仅当
x
x
x在这些点的凸包上(是刚好在表面上而非内部。)
探索在凸包上的条件:
1.
∑
x
=
n
(
n
+
1
)
2
\sum x = \frac {n(n+1)}2
∑x=2n(n+1)
2.
∑
i
=
1
k
y
i
≥
k
(
k
+
1
)
2
\sum_{i=1}^k y_i \geq \frac {k(k+1)}2
∑i=1kyi≥2k(k+1),其中
y
y
y是给
x
x
x按从小到大排序得到的数组。
这两个条件都是必要的。
第二个条件,因为前
k
k
k个位置的和如果
<
k
(
k
+
1
)
2
\lt \frac{k(k+1)}2
<2k(k+1)的话,就算选了
n
n
n个排列每个排列的前
k
k
k个都尽量小,总和也有
k
(
k
+
1
)
n
2
\frac {k(k+1)n}2
2k(k+1)n,不能更小,所以两边在前
k
k
k位的和都对不上,更别提对位相等了。
断言:满足这两个条件的序列
x
x
x一定可以被构造出来。(充分性存在)
构造方案如下:
每次把
x
x
x排好序,考虑把
x
x
x减去一个
p
,
2
p
,
3
p
.
.
.
.
n
p
p,2p,3p....np
p,2p,3p....np(就是一个
1
1
1到
n
n
n的排列乘上
p
p
p)。
考虑减去后仍可以被
n
−
1
n-1
n−1个排列构造出来的条件:
1.
∑
x
=
n
(
n
+
1
)
2
(
1
−
p
)
\sum x = \frac {n(n+1)}2(1-p)
∑x=2n(n+1)(1−p)
2.
∑
i
=
1
k
y
i
≥
k
(
k
+
1
)
2
(
1
−
p
)
\sum_{i=1}^k y_i \geq \frac {k(k+1)}2 (1-p)
∑i=1kyi≥2k(k+1)(1−p)
那么二分出最大的
p
p
p使得
x
x
x被减少后排序后满足上列条件。
这样的
p
p
p可以使得至少一个实际上
∑
i
=
1
k
x
i
>
k
(
k
+
1
)
2
\sum_{i=1}^k x_i \gt \frac {k(k+1)}2
∑i=1kxi>2k(k+1)的位置
k
k
k
在减少之后满足
∑
i
=
1
k
y
i
=
k
(
k
+
1
)
2
(
1
−
p
)
\sum_{i=1}^k y_i = \frac {k(k+1)}2(1-p)
∑i=1kyi=2k(k+1)(1−p)
可以推推式子证明任何
∑
i
=
1
k
x
i
=
k
(
k
+
1
)
2
\sum_{i=1}^k x_i =\frac {k(k+1)}2
∑i=1kxi=2k(k+1)的位置
k
k
k
在减少之后满足
∑
i
=
1
k
y
i
=
k
(
k
+
1
)
2
(
1
−
p
)
\sum_{i=1}^k y_i = \frac {k(k+1)}2(1-p)
∑i=1kyi=2k(k+1)(1−p)
所以减一次就会少一个实际上大于的位置。
一开始在
n
n
n的位置就是等于。
所以经过了
n
−
1
n-1
n−1次就一定会变成
1...
n
1...n
1...n每个位置都是等于。
这个时候减一个
p
,
2
p
,
3
p
.
.
.
.
n
p
p,2p,3p....np
p,2p,3p....np就可以直接消为
0
0
0。
会发现这个方案在满足初始条件的情况下会一直满足,构造到全变为
0
0
0。
所以证明成立。
A
C
C
o
d
e
\mathcal AC \ Code
AC Code
#include<bits/stdc++.h>
#define maxn 505
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define db double
#define eps 1e-12
#define LL long long
using namespace std;
int n,c[maxn],c2[maxn];
db x[maxn],p[maxn],x2[maxn];
int y[maxn][maxn];
bool cmp(const int &u,const int &v){ return x[u] < x[v]; }
bool cmp2(const int &u,const int &v){ return x2[u] < x2[v]; }
int main(){
freopen("permutation.in","r",stdin);
freopen("permutation.out","w",stdout);
scanf("%d",&n);
rep(i,1,n)scanf("%lf",&x[i]),c[i]=i;
db rs = 1;
rep(i,1,n){
sort(c+1,c+1+n,cmp);
memcpy(c2,c,sizeof c2);
db L = 0 , R = rs , mid;
for(;(R-L) > eps;){
mid = (L+R) * 0.5;
rep(j,1,n) x2[c[j]] = x[c[j]] - j * mid;
sort(c2+1,c2+1+n,cmp2);
db sm = 0;
bool ER = 0;
rep(j,1,n){
sm += x2[c2[j]];
if(sm < (rs - mid) * j * (j+1) / 2 - eps){
ER = 1;
break;
}
}
if(ER) R = mid - eps;
else L = mid;
}
p[i] = L;
if(i == n) p[i] = rs;
rs -= p[i];
rep(j,1,n) x[c[j]] -= p[i] * j;
rep(j,1,n) y[i][c[j]] = j;
// rep(j,1,n) printf("%.3lf%c",x[j]," \n"[j==n]);
}
if(rs > 1e-6){
puts("-1");
return 0;
}
rep(i,1,n) if(fabs(x[i]) > 1e-2){
puts("-1");
return 0;
}
printf("%d\n",n);
rep(i,1,n){
printf("%.10lf ",p[i]);
rep(j,1,n) printf("%d%c",y[i][j]," \n"[j==n]);
}
}