散々なことをやりまくって時間を溶かしてしまいました
解説
ANDをとるので、選んだK個全てで立っているBITのみが残る
ANDの最大値をとるので、最高ビットを残すことが最優先
すべての部分列を列挙()
上のビットから順番に見ていって、そのビットが立っているような部分列がK個以上あればそのビットを残すことに決める
そして、そのビットが立っている部分列のみをK個の候補に残し、下位のビットに移る
一種の貪欲といえるのかな
部分和の最大値はなので、longを使います
計算量は、部分列が個、見るビットの数が個、僕はsetを使ったのでここにが加わって、でした。
実装を上手くやるとまでおちると思います。2桁msで通してる人のコードを読むと大体わかります
long n, m;
long a[1005];
long sum[1005];
long psum[2000000];
long bitflag = 1;
int main(){
scanf("%ld%ld", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%ld", &a[i]);
sum[i] = sum[i-1] + a[i];
}
long pcnt = 0;
for(int i = 0; i <= n; i++){
for(int j = i+1; j <= n; j++){
psum[pcnt] = sum[j] - sum[i];
pcnt++;
}
}
long upmost = 0;
for(long bitflag = 1; bitflag < 35184372088832; (bitflag <<= 1)){
int cnt = 0;
for(int i = 0; i < pcnt; i++){
if(bitflag & psum[i]){
cnt++;
}
}
if(cnt >= m){
upmost = bitflag;
}
}
if(upmost == 0){
printf("0\n");
return 0;
}
std::set<int> st;
for(int i = 0; i < pcnt; i++){
st.insert(i);
}
while(upmost > 0){
int cnt = 0;
for(auto i = st.begin(); i != st.end(); i++){
if(psum[*i] & upmost){
cnt++;
}
}
std::set<int> st2;
if(cnt >= m){
for(auto i = st.begin(); i != st.end(); i++){
if(psum[*i] & upmost){
st2.insert(*i);
}
}
st = st2;
st2.clear();
}
upmost >>= 1;
}
long ans = psum[*st.begin()];
for(auto i = st.begin(); i != st.end(); i++){
ans = (ans & psum[*i]);
}
printf("%ld\n", ans);
}
感想/反省
ANDをORと勘違いしたり、setの要素をeraseしようとして散々バグらせたり、自作のビジュアライズ関数がバグってたり、散々なことになってしまいました。問題を解き続けることが必要だなと感じました。次はレートあげたいぞ〜