1. 程式人生 > >題解 CF734F 【Anton and School】

題解 CF734F 【Anton and School】

n) getc school pen clu 情況 == for tdi

題解 CF734F 【Anton and School】

傳送門

這種將位運算和普通運算結合起來的題目要拆位來考慮,可以得到\(log_{2}(\)值域\()\)的算法,甚至將值域看成常數。

根據

\(a|b+a \& b=a+b\)

得到

\(b_i+c_i=\Sigma a_i+na_i\)

於是

\(a_i=\frac{b_i+c_i- \Sigma a_i}{n}\)

根據這個式子,直接得到\(a_i\),註意在除的時候判斷整除以免非法情況出現。

此時,我們要判斷\(b_i\)\(c_i\)是否真的合法,考慮到位運算的性質,我們開個\(cnt[x]\),記錄所有\(a_i\)

在二進制第\(x\)位出現的次數,此時,我們只需要檢驗——

\(b_i=2^k \times cnt[k]\)

\(c_i=\Sigma a_i+2^k \times (n-cnt[k])\)

這裏的\(k\)滿足

\(a_i\&(1<<(k-1))\)

總復雜度\(O(nlog(\)值域\())\),相當於\(O(n)\),但理論上會爆\(unsigned\) \(long\) \(long\) 但是它沒有爆。

極其醜陋的代碼

#include<bits/stdc++.h>

#define RP(t,a,b) for(register int (t)=(a),edd_=(b);t<=edd_;++t)
#define qit return puts("-1"),0

using namespace std;typedef unsigned long long ll;
template<class ccf> inline ccf qr(ccf k){
    char c=getchar();
    ccf x=0;
    int q=1;
    while(c<48||c>57)q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
    return q==-1?-x:x;
}

const int maxn=200005;
ll a[maxn];
ll b[maxn];
ll c[maxn];
ll cnt[65];
ll n;ll sum;

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    n=qr(1);
    RP(t,1,n)
    b[t]=qr(1ll);
    RP(t,1,n)
    c[t]=qr(1ll);
    RP(t,1,n)
    sum+=b[t]+c[t];
    if(sum%(n<<1))
    qit;
    sum/=(n<<1);
    RP(t,1,n){
    a[t]=b[t]+c[t]-sum;
    if(a[t]%n)
        qit;//宏
    else
        a[t]/=n;
    RP(i,1,63)
        if((a[t]&(1ll<<(i-1))))
        cnt[i]++;
    }
    
    ll temp=0;
    RP(t,1,n){
    temp=0;
    RP(i,1,63)
        if(a[t]&(1ll<<(i-1)))
        temp+=cnt[i]*(1ll<<(i-1));
    if(temp!=b[t])
        qit;//宏
    temp=sum;
    RP(i,1,63)
        if(a[t]&(1ll<<(i-1)))
        temp+=(n-cnt[i])*(1ll<<(i-1));
    if(temp!=c[t])
        qit;//宏
    }
    
    RP(t,1,n)
    cout<<a[t]<<‘ ‘;
    puts("");
    return 0;
}
 

題解 CF734F 【Anton and School】