哭死,比賽的時候完全想歪了,想的是考慮一次合併能造成多大的貢獻,按照貢獻排序然後合併。這樣做只能考慮區域性造成的貢獻,然而最後算的時候要考慮整體,所以並不是很對。
正著想沒有思路就可以倒著想,考慮列舉答案。
合併k次,意味著最後是n-k個數。
經典從二進位制高位到低位考慮,考慮這一位(假設為第i位)能否出現在答案裡?那我們就讓原序列最後合併完後的數每個數第i位都是1,在此要求下讓合併完的數儘可能的多(只要最後留下的數的個數大於等於n-k就可以,然後我們就能接著考慮二進位制下一位)。怎們考慮讓合併完的數儘可能的多?我們設nt[now][j]表示第now個數及以後最早出現“二進位制第j位為1”的位置在哪,就很好讓最後合併完的數儘可能多了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,ans;
const int N=200010;
int a[N],nt[N][32],las[233];
int pan(int c)
{
int cnt=0,now=1;
while(now<=n)
{
int maxx=0;
for(int j=1;j<=31;++j)
if((c>>(j-1))&1)
{
maxx=max(maxx,nt[now][j]);
}
//cout<<" -> "<<now<<" "<<maxx<<endl;
if(maxx<=n)++cnt,now=maxx+1;
else break;
}
return cnt>=k;
}
signed main()
{
cin>>n>>k;k=n-k;
for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
for(int i=1;i<=31;++i)las[i]=n+1;
for(int i=n;i>=1;--i)
{
for(int j=1;j<=31;++j)
if((a[i]>>(j-1))&1)las[j]=i;
for(int j=1;j<=31;++j)nt[i][j]=las[j];//,cout<<"-- "<<i<<" "<<j<<" "<<nt[i][j]<<endl;
}
for(int i=31;i>=1;--i)
{
ans|=(1ll<<(i-1));
if(pan(ans)==0)ans^=(1ll<<(i-1));
}
cout<<ans;
return 0;
}
/*
5 2
2 1 2 3 1
20 7
46734244 7155744 419668125 71371568 686112 90931877 235739656 174560001 73941537 157614741 557848156 172496544 449681808 258216481 628704657 317530505 436971280 329908401 168398248 163412001
4194304
*/