HDU 5270 归并排序

来源:互联网 发布:java把两个数组合并 编辑:程序博客网 时间:2024/06/04 18:10
问题描述
ZYB喜欢研究Xor,现在他得到了两个长度为n的数组A,B。于是他想知道:对于所有数对(i,j)(i[1,n],j[1,n])(Ai+Bj)的xor之和为多少定义多个数A1,A2...Akxor之和为A1xorA2xorA3xor...xorAk
输入描述
一共T(T10)组数据,对于每组数据:第一行一个正整数n,表示数组长度第二行n个非负整数,第i个整数为Ai第三行n个非负整数,第i个整数为Bin[1,105]Ai,Bi[0,260]保证所有n的和小于等于2105
输出描述
每组数据输出一行Case #x: ans。x表示组数编号,从1开始。ans为所求值。
输入样例
158 11 30 28 028 27 22 0 0
输出样例
Case #1: 34
1003 ZYB loves Xor II我们考虑两个数AB。为了描述方便,我们设[P]的值为:当表达式P的值为真时,[P]=1,否则[P]=0我们现在考虑计算[(A+B)and(2i)>0]首先我们将A,B都对2i+1取模,显然这样是不会影响答案的则有一个十分显然的等式:[(A+B)and(2i)>0]=[(A+B)(2i)][(A+B)(2i+1)]+[(A+B)(32i)]这个式子相当容易理解,这里不多述了考虑每一位对答案的贡献是独立的,我们每一位分开做于是现在问题变成了:给定数组A,B,求满足Ai+Bjlimit的数对个数我们可以将A,B排序后,直接O(n)计算即可然而排序是O(nlogn)的,这样总复杂度就是O(nlognlogA)了,无法通过此题于是这里有个小技巧我们从高位往低位做,现在我们要实现的是:将A中每个数对P取模后将A排序我们发现A会被分成两段,一段小于P,一段大于等于P,只有后面一段要取模,我们可以取模后直接将这两段归并,复杂度是O(n)的时间复杂度:O(nlogA+nlogn)

此题注意位运算的大量使用,很省时间,而且容斥的想法和转化很巧妙。
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string.h>#include<vector>#include<algorithm>#define ll __int64#define maxn 110000using namespace std;vector<ll>q[2];ll x[maxn],y[maxn];ll bit[100];int n;ll solve()//我擦。。这个归并太吊了{    ll ans=0;    for(ll i=0;i<62;i++)    {        ll tot=0;        q[0].clear();q[1].clear();        for(ll j=1;j<=n;j++)            q[(x[j]>>i)&1].push_back(x[j]);        for(ll j=0;j<q[0].size();j++)            x[++tot]=q[0][j];        for(ll j=0;j<q[1].size();j++)            x[++tot]=q[1][j];        tot=0;        q[0].clear();q[1].clear();        for(ll j=1;j<=n;j++)            q[(y[j]>>i)&1].push_back(y[j]);        for(ll j=0;j<q[0].size();j++)            y[++tot]=q[0][j];        for(ll j=0;j<q[1].size();j++)            y[++tot]=q[1][j];        ll len1=1,len2=1,len3=1;        ll limit1=1ll<<i;        ll limit2=1ll<<(i+1);        ll all=(1ll<<(i+1))-1;///这里加1LL//        cout<<all<<" all"<<endl;        ll sum=0;//        for(int i=1;i<=tot;i++) cout<<x[i]<<" ";//        cout<<endl;//        for(int i=1;i<=tot;i++) cout<<(x[i]&all)<<" ";//        cout<<endl;//        for(int i=1;i<=tot;i++) cout<<y[i]<<" ";//        cout<<endl;        for(ll i=n;i>=1;i--)        {            while((((x[i]&all)+(y[len1]&all))<limit1) && (len1<=n)) len1++;//这里多加几个()            while((((x[i]&all)+(y[len2]&all))<limit2) && (len2<=n)) len2++;            while(((x[i]&all)+(y[len3]&all)<limit1+limit2) && (len3<=n)) len3++;//cout<<(x[i]&all)<<" "<<(y[len3]&all)<<" "<<len3<<" "<<y[len3]<<" "<<(limit1+limit2)<<endl;            sum+=n-(len1-1-len2+1+len3-1);//            cout<<len1<<" "<<len2<<" "<<len3<<endl;//            cout<<n-(len1-1-len2+1+len3-1)<<endl;        }//        cout<<sum<<" sum   "<<i<<endl;        if(sum&1) ans+=bit[i];    }    return ans;}int main(){//    freopen("1003.txt","r",stdin);    int cas;    scanf("%I64d",&cas);    bit[0]=1;    for(ll i=1;i<=61;i++)    bit[i]=bit[i-1]*2;    for(ll ca=1;ca<=cas;ca++)    {        scanf("%I64d",&n);        for(ll i=1;i<=n;i++)            scanf("%I64d",&x[i]);        for(ll i=1;i<=n;i++)            scanf("%I64d",&y[i]);//        cout<<solve()<<endl;       printf("Case #%I64d: %I64d\n",ca,solve()) ;    }}


                                             
0 0