hdu 5798 Stabilization

本文介绍了一种高效算法,用于计算一组二元组与特定数值进行XOR运算后的不稳定度总和。通过预处理二元组中各二进制位的组合情况,实现了O(log n)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

考虑如何快速求出一堆二元组xor某数之后求差的和,因为ab=i=02i(abibbi)abi表示a二进制第i位的值),所以只需要记录这些二元组二进制表示中每一位上四种01组合的种数,就可以在O(logn)下求出结果。
因为题目求的是差的绝对值,而两数只有在他们最高的不同位被xor时才会改变大小关系,故可以按照二元组的最高的不同位将其分为O(logn)种。这样,只需要O(log2n)就可以计算出一个数组xor某数后的instability。
考虑通过枚举x来求出结果,无脑枚举的复杂度是O(MAXailog2n),跑极限数据和自杀差不多。观察求某个x的结果的过程,发现这一过程是可以通过递推求取的,这样就可以在O(MAXailogn)下通过了。

#include<algorithm>
#include<iostream>
#include<climits>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
#define clr(a) memset(a,0,sizeof(a))
const ll md=1000000007;
int ar[100000],n,sr[20][20][2][2];ll xr[1<<20],tr[1<<20],xsr[20][20][2][2];
int _cl(int x){
    int i=19,j=1<<19;for(;i>=0&&!(x&j);j>>=1,--i);
    return i;
};
ll _cl(int d,int k,int v,bool fg){
    int i,j;ll r;for(r=0,i=0;i<2;++i)for(j=0;j<2;++j){
        r+=sr[d][k][i][j]*(fg?(j^v)-(i^v):(i^v)-(j^v));
    }
    return (ll)r*(1<<k);
};
void _cl(int d,int v){
    int i,j,t,a,b;ll r;
    for(i=19,j=1<<19;!(v&j);j>>=1,--i);r=xr[v^j];
    if(d==i)for(xr[v]=0,j=0;j<20;++j)xr[v]+=xsr[d][j][v&(1<<j)?1:0][1];
    else{
        r-=xsr[d][i][0][v&(1<<d)?1:0];r+=xsr[d][i][1][v&(1<<d)?1:0];xr[v]=r;
    }
};
void __cl(int d){
    int i,j,t,a,b;for(clr(sr),i=1;i<n;++i){
        t=_cl(ar[i]^ar[i-1]);if(t<0)continue;
        a=ar[i],b=ar[i-1];if(a<b)swap(a,b);
        for(j=0;j<20;++j)sr[t][j][a&(1<<j)?1:0][b&(1<<j)?1:0]++;
    }
    for(i=0;i<20;++i)for(j=0;j<20;++j)for(t=0;t<2;++t)
        xsr[i][j][t][0]=_cl(i,j,t,0),xsr[i][j][t][1]=_cl(i,j,t,1);
    for(clr(tr),i=0;i<20;++i){
        for(xr[0]=0,j=0;j<20;++j)xr[0]+=xsr[i][j][0][0];tr[0]+=xr[0];
        for(j=1;j<=d;++j){_cl(i,j);tr[j]+=xr[j];}
    }
};
void cl(){
    int i,j,a,d;ll t,r;scanf("%d",&n);
    for(i=0;i<n;scanf("%d",&ar[i++]));
    for(d=ar[0],i=1;i<=n;d=max(d,ar[i++]));__cl(d);
    for(r=LLONG_MAX,i=0;i<=d;++i)if(tr[i]<r)
        r=tr[i],a=i;
    printf("%d %I64d\n",a,r);
};
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int t;scanf("%d",&t);
    while(t--)cl();
    return 0;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值