WA 最后一个点。
大体思路:
m=0 和 m=0 时分别讨论。
m=0 时,由于除了最后一层,其他层节点都是满的,因此可以先删最后一层之后一层层删,直至超过 m 或输出 −1。
m=0 时,若该树本身即为满二叉树,直接计算答案,否则先算满二叉树部分,再用分治计算最后一次剩余节点编号之和后计算答案即可。
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
ll x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')y=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch&15),ch=getchar();
return x*y;
}
int t;
ll n,m,ans;
ll f(ll a,ll b){
if(b<=1||a==1)return 0;
if(a==2)return 1;
if(a==b)return (a-1)*a/2;
if(b>a/2)return 2*f(a/2,a/2)+2*f(a/2,b-a/2)+b-a/2;
return 2*f(a/2,b);
}
int main(){
t=read();
while(t--){
n=read();m=read();
ll k=1,d=1;
while(k*2<=n)d++,k=k*2;
if(m){
ll t=(n-k)*2;
m-=t;
if(m<=0){
ans=k*(2*k-1)/d;
}else{
while(m>0&&k>1){
t=k;
m-=t;
k/=2;
d--;
}
if(m>0)ans=-1;
else ans=k*(2*k-1)/d;
}
}else{
if(n==k){
ans=k*(2*k-1)/d;
}else{
d++;
ll fuck=1ll*(f(k,n-k)+k*(n-k))*4+n-k;
ans=(ll)(k*(2*k-1)+fuck)/d;
}
}
printf("%lld\n",ans);
}
return 0;
}
和 官方题解 对拍了一下发现了一个 WA 的数据:
2
16 0
17 0
官方题解:
99
99
我的输出:
99
93
求调。