#370 [UR#17]おかしいおかしいの果樹UOJ

タイトル

チリの選手たちは本当に低いブラシがUOJ動きません

どうやら連鎖の一番下にリンクされている、あなたに嘘をつくプレー、ビット単位とこの事はますます小さくなっている最初のツリーの構造を検討することは、明らか下記ぶら下がっ前に特定のポイントに劣っていないので、我々はちょうどを求めます配置された最小の十分な答えは、このような

セット\(A = \最大(a_iを)\) 最良の答えは、より劣っであることが判明することはできません繰り返し数をとる(RMと\ \)\を答え、我々は持っている\(O(NA)を\)暴力、聞かせて\(dp_i \)は、現在の示し(RMと\ \)\をとして、\(私は\) この\は(私は\)になり(0 \)\最小コストを

しかし、そこに最後かもしれ(RMと\ \)\とない\(0 \)ので、我々はすべて入れ\(a_iをを\)共通ビットです\(k個\)ごとに求めている(\ a_iを\)これらの数字を排除する、つまり、とする\(K \) XORビット、そして最後にRMと\ \ \() 我々はようになります\(0 \) ;答えプラスで\(N \を\回K)上良く

この場合、転送は非常に簡単で、我々は、列挙\(a_j \)、\ (dp_i = \分(dp_ a_j + I)のRMと\ a_jを\ \ {IのRMとを\ \ \} \)への

最後に、答えは\(\分(dp_ {a_iを } + a_iを)\)

通知\(I \ \ RMと\ a_j \) する必要があります\(私は\)サブセット、考える列挙\(I \)の部分集合\(J \) 今だけがあるかどうかを判断する必要があります\は( a_k \)を満たすには、\(私はRMと\ \ \ \ a_k = j個\)

セットの観点から考慮、我々はその条件の上に置くことができますがに分割された\(Jは\)です\(a_k \)サブセット、および\(\ a_k)される(bigoplus私は\ jは\)\集中コーパスの補数でサブセットは、我々が使用する\(\ RM FWT \)あなたがそこにあるかどうかを知ることができるものとの契約\(a_kが\)された(私はbigoplus J \ \)\、集中フルセットアップのサブセットを、しかし決定する方法はありません\(jは\)かどうか\(a_k \)サブセット

しかし、それについて考え、私たちは判断する必要見つからない\(J \)かどうか\(a_k \)だけ転送のように、サブセットを

観察転送タイプ\(dp_i = \分(dp_j + J)\) 明らかに\(J \)そのようなものの存在を介するなど、可能な限り小さく\(a_k \)\(iはbigoplus J \ \)補体レパートリー濃縮サブセットは、しかし、\(\ a_k)ない\(J \)サブセットが、そこであろう小さい(iは\)\サブセットである\(\ a_k)特定の転送のサブセットよりよいです

より非常に複雑\(O(3 ^ {\ログA})\)

#include<bits/stdc++.h>
#define re register
#define LL long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=1e5+5;
int n,a[maxn],vis[1<<18+1],k,T,len;
LL dp[1<<18+1],ans;
int main() {
    n=read();
    for(re int i=1;i<=n;i++) a[i]=read(),T=max(T,a[i]);
    len=1;while(len<T) len<<=1;len--;
    for(re int i=1;i<=n;i++) vis[a[i]]=1;
    for(re int i=2;i<=len+1;i<<=1)
        for(re int ln=i>>1,l=0;l<len;l+=i)
            for(re int x=l;x<l+ln;++x) vis[x+ln]|=vis[x];
    k=a[1];for(re int i=2;i<=n;i++) k&=a[i];
    for(re int i=1;i<=n;i++) a[i]^=k;
    memset(dp,20,sizeof(dp));
    ans=dp[0];dp[0]=0;
    for(re int i=1;i<=T;i++) 
        for(re int j=i;j;j=(j-1)&i)
            if(vis[len^j]&&dp[i^j]+(i^j)<dp[i]) dp[i]=dp[i^j]+(i^j);
    for(re int i=1;i<=n;i++) 
        ans=min(ans,dp[a[i]]+a[i]);
    printf("%lld\n",1ll*n*k+ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/asuldb/p/11388166.html