题解:P17227 [Math×Girl²] まよいづき
挖吧会证明,只能说说我咋做的了呜呜呜。
首先你发现
我们尝试一个答案下界,我们猜测每轮扔掉最轻的那个和最重的那些,轻的可以足够轻,于是我们得到答案不小于
接下来,我们把我们上面的构造坐下来,每次保留形如一个区间,做完之后算出来最轻的那个最重是啥,我们此处允许负数,最后再加即可,我们观察到为了让这个人轻被影响小,于是重的那边尽量轻,于是我们要求对于
然后我们思考一下还能怎么卡,我们发现我们每次如果轻的那个和最轻的几个
我们思考一下这个值具体是什么?
实际上我们只关心下一轮物品总和,我们设
于是每一轮物品总和类似一个负数,是后一轮物品总和的两倍减一。最后物品总和是
我这个最轻物品重量就是物品总和减去重的那些物品,我们希望最后一轮这个值大一点。
我们考虑为啥会发生不单调降。
容易看出物品总和是
而减去的重量是
考虑每一轮找重物品个数是前一轮一半。
我们考虑
第二轮拿的物品少一半,就是
于是前两轮很难受。
我们发现可以把这两轮平均一下,我们无法做到更优秀,即使只考虑这两轮,平均下来是
于是平均一下,发现过了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int m[2000009];
int t[2000009];
int n;
int f[2000009];
int g[2000009];
int w[29];
void did(int x){
int r;
r=(1ll<<(n-x+1))-(n-x+1)-1;
if(r+n-x+2==4){
t[f[r]]=t[(1ll<<n)-x+1]=x;
t[(1ll<<n)-n+1]=x+1;
t[(1ll<<n)-n]=0;
m[(1ll<<n)-n+1]=-1;
m[(1ll<<n)-x+1]=-m[f[r]]-2;
return;
}
int rr;
rr=(1<<(n-x))-(n-x+1);
t[(1ll<<n)-x+1]=x;
if(n>=4&&x==1){
int rrr;
rrr=(1ll<<(n-x-1))-(n-x);
int S,T;
S=T=0;
for(int i=rrr+1;i<=rr;i++){
T+=m[f[i]];
}
for(int i=rr+1;i<=r;i++){
S+=m[f[i]];
}
int zz1,zz2;
zz1=rrr+1,zz2=r;
S-=T;
while(w[3]>S){
if(S+2*(zz2-zz1)<w[3]){
S+=2*(zz2-zz1);
swap(f[zz1],f[zz2]);
++zz1,--zz2;
continue;
}
while(zz1+1<=rr&&S+2*(zz2-zz1-1)>=w[3]){
++zz1;
}
while(zz2-1>rr&&S+2*(zz2-zz1-1)>=w[3]){
--zz2;
}
swap(f[zz1],f[zz2]);
break;
}
}
for(int i=rr+1;i<=r;i++){
t[f[i]]=x;
}
did(x+1);
int sum;
sum=-1;
for(int i=1;i<=rr;i++){
sum+=m[f[i]];
}
for(int i=(1ll<<n)-n;i<=(1ll<<n)-x;i++){
sum+=m[i];
}
for(int i=rr+1;i<=r;i++){
sum-=m[f[i]];
}
m[(1ll<<n)-x+1]=min(sum,m[(1ll<<n)-x]-1);
}
void _main(){
cin>>n;
cout<<(1ll<<n)-n<<endl;
m[(1ll<<n)-n]=0;
for(int i=(1ll<<n)-n-1;i>=1;i--){
m[i]=m[i+1]+1;
}
for(int i=1;i<=(1ll<<n)-n-1;i++){
f[i]=i;
}
w[n]=-1;
for(int i=n-1;i>=1;i--){
w[i]=w[i+1]*2-1;
}
//w[3]<=S-T
if(n>1)
did(1);
else
t[1]=0,t[2]=1,m[1]=0,m[2]=-1;
for(int i=1;i<=(1ll<<n);i++){
cout<<m[i]-m[(1ll<<n)]+1<<" ";
}
cout<<endl;
for(int i=1;i<=(1ll<<n);i++){
cout<<t[i]<<" ";
}
cout<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
_main();
}
return 0;
}