数学(Anton and School,cf 734F)

来源:互联网 发布:网络教育 高起专 时间 编辑:程序博客网 时间:2024/04/26 18:32

首先要知道          (a&b)+(a|b)=a+b          ①

我也不知道怎么才能想到这个,只能说按位运算是有很多规律的,以后遇到类似的题可以尝试着去寻找一些规律。


讲解:

已知         b[i]=∑(a[i]&a[j]),(1<=j<=n)

                c[i]=∑(a[i]|a[j]),(1<=j<=n)


设d[i]=b[i]+c[i],

根据公式①,易得          d[i]=b[i]+c[i]=∑(a[i]&a[j])+∑(a[i]|a[j])=∑(a[i]&a[j]+a[i]|a[j])

                                                    =∑(a[i]+a[j])=n*a[i]+a[1]+a[2]+...+a[n],(1<=j<=n)

即                                  d[i]=n*a[i]+a[1]+a[2]+...+a[n]          ②

所以         ∑d[i]= ∑(b[i]+c[i])=∑(n*a[i]+a[1]+a[2]+...+a[n])=2n*(a[1]+a[2]+...+a[n])

即             a[1]+a[2]+...+a[n]=∑d[i]/(2n)          ③


讲③带入②,解得          a[i]=(d[i]-(∑d[i])/(2n))/n。

然后循环一遍就能求出唯一的a[i]。

但是要注意这个a[i]只是满足d[i],却不一定满足b[i]与c[i]。

所以要一定检查一遍,如果这个解同时也满足b[i]与c[i],那么就输出之,否则就无解。


至于检查的方式也是很有趣,如果带入原公式O(n^2)计算那就超时了。

方法是按位计算。因为计算公式很有特点,所以一个O(n)的循环就可以用一个O(1)的计算搞定,但付出的代价是必须一位一位的算。最终算法时间复杂度位O(nL),其中L是二进制位数。显然long long也就才64位啦。


a[i][j]表示第i个a的第j位,显然只能为0或者为1。b[i][j],c[i][j]同理。

bit[i]表示第i位是1的a的个数。

那么有b[i][k]=∑(a[i][k]&a[j][k]),(1<=j<=n,0<=k<L)

以及   c[i][k]=∑(a[i][k]|a[j][k]),(1<=j<=n,0<=k<L)

那么我们很容易就找到了这个O(1)计算的公式。

b[i][k]=a[i][k]?bit[k]:0

c[i][k]=a[i][k]?n:bit[k]


最后B[i]=∑(b[i][k]<<k)

以及C[i]=∑(c[i][k]<<k)


然后把B[i],C[i],与b[i],c[i]对比一下就知道答案是否符合了。


代码

#include<bits/stdc++.h>#define maxn 200100using namespace std;typedef long long ll;ll n;ll a[maxn],b[maxn],c[maxn],d[maxn];ll A[maxn][70],bit[70],B[maxn],C[maxn];bool ok(){    for(ll i=1;i<=n;i++)        if(a[i]<0)            return false;    for(ll i=1;i<=n;i++)        for(ll j=0;j<63;j++)        {            A[i][j]=a[i]&(1ll<<j)?1:0;            bit[j]+=A[i][j];        }    for(ll i=1;i<=n;i++)        for(ll j=0;j<63;j++)        {            ll bbit=A[i][j]?bit[j]:0;            ll cbit=A[i][j]?n:bit[j];            B[i]+=bbit<<j;            C[i]+=cbit<<j;        }    for(ll i=1;i<=n;i++)        if(B[i]!=b[i]||C[i]!=C[i])            return false;    return true;}void print(){    for(ll i=1;i<=n;i++)        printf("%I64d%c",a[i],i==n?'\n':' ');}int main(){    scanf("%I64d",&n);    for(ll i=1;i<=n;i++)        scanf("%I64d",&b[i]);    for(ll i=1;i<=n;i++)    {        scanf("%I64d",&c[i]);        d[i]=b[i]+c[i];    }    ll sum=0;    for(ll i=1;i<=n;i++)        sum+=d[i];    sum/=(2*n);    for(ll i=1;i<=n;i++)        a[i]=(d[i]-sum)/n;    if(ok()) print();    else puts("-1");    return 0;}


0 0