题目:
有一个排列
p
p
p,有一种操作:选择两个数
i
,
j
i,j
i,j,满足
i
≠
j
,
p
j
=
i
i \ne j,p_j=i
i=j,pj=i,然后
s
w
a
p
(
p
i
,
p
j
)
swap(p_i,p_j)
swap(pi,pj),代价为
(
j
−
i
)
2
(j-i)^2
(j−i)2。不停地对排列
p
p
p做以上操作,直到满足
p
i
=
i
,
∀
i
∈
[
1
,
n
]
p_i=i, \forall i \in [1,n]
pi=i,∀i∈[1,n]。
要你给出一个排列
p
p
p,和相对应的操作序列,使代价最大。
(
2
≤
n
≤
1
0
5
)
(2 \le n \le 10^5)
(2≤n≤105)
题解:
我一开始想的是对于每一种排列都有一种固定的贪心方法,然后我们再贪出代价最大的排列,把问题想的很复杂。
这道题可以逆过来做,考虑原排列为
1
,
2
,
3
,
.
.
.
,
n
1,2,3,...,n
1,2,3,...,n,我们有一个操作:选择一个
i
i
i满足
p
i
=
i
p_i=i
pi=i,然后选择任意一个
j
j
j满足
j
≠
i
j \ne i
j=i,然后
s
w
a
p
(
p
i
,
p
j
)
swap(p_i,p_j)
swap(pi,pj),代价为
(
j
−
i
)
2
(j-i)^2
(j−i)2。然后我们用这个操作将原排列乱序,直至没有数在原来的位置上了为止。显然我们最多可以操作
n
−
1
n-1
n−1次,因为第一次操作肯定是两个在原来位置上的数互换。考虑每个位置可以产生的最大贡献,1和
n
n
n最大可以产生
(
n
−
1
)
2
(n-1)^2
(n−1)2的贡献,但是两者之间只能有一个产生贡献,2和
n
−
1
n-1
n−1可以产生
(
n
−
2
)
2
(n-2)^2
(n−2)2的贡献,3和
n
−
2
n-2
n−2可以产生
(
n
−
3
)
2
(n-3)^2
(n−3)2的贡献,依此类推。如果1不产生
(
n
−
1
)
2
(n-1)^2
(n−1)2的贡献,那
n
n
n也不会产生
(
n
−
1
)
2
(n-1)^2
(n−1)2的贡献,那么假设1和
n
n
n都产生
(
n
−
2
)
2
(n-2)^2
(n−2)2的贡献,当
i
≥
1
i \ge 1
i≥1时,
i
2
>
2
(
i
−
1
)
2
i^2 >2 (i-1)^2
i2>2(i−1)2,所以不如产生
(
n
−
1
)
2
(n-1)^2
(n−1)2的贡献,综上,我们得到了一个代价的上界。我们考虑构造操作序列达到这个上界,那么可以先
(
1
,
n
)
(1,n)
(1,n)贡献
(
n
−
1
)
2
(n-1)^2
(n−1)2,再
(
2
,
n
)
(2,n)
(2,n)贡献
(
n
−
2
)
2
(n-2)^2
(n−2)2,再
(
n
−
1
,
1
)
(n-1,1)
(n−1,1)贡献
(
n
−
2
)
2
(n-2)^2
(n−2)2,再
(
3
,
n
)
(3,n)
(3,n)贡献
(
n
−
3
)
2
(n-3)^2
(n−3)2……最后输出操作后的序列
p
p
p,逆向输出操作序列。
复杂度: O ( n ) O(n) O(n)
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
//#include<unordered_map>
using namespace std;
#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;
ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int t,n;
int p[maxn];
vector<pii>ans;
int main(void){
// freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
p[i]=i;
}
ans.clear();
ll cost=0;
swap(p[1],p[n]);
ans.pb(mp(1,n));
cost+=1ll*(n-1)*(n-1);
for(int i=2;i<=n/2;i++){
swap(p[i],p[n]);
ans.pb(mp(i,n));
swap(p[n-i+1],p[1]);
ans.pb(mp(n-i+1,1));
cost+=2ll*(n-i)*(n-i);
}
if(n%2==1){
swap(p[n/2+1],p[1]);
ans.pb(mp(n/2+1,1));
cost+=1ll*(n/2)*(n/2);
}
printf("%lld\n",cost);
for(int i=1;i<=n;i++)printf("%d ",p[i]);
puts("");
printf("%d\n",sz(ans));
for(int i=sz(ans)-1;i>=0;i--){
printf("%d %d\n",ans[i].fi,ans[i].se);
}
}
return 0;
}