読者です 読者をやめる 読者になる 読者になる

tookunn’s diary

主に競技プログラミング関係

Codeforces #320 Div2 D

Codeforces

問題

http://codeforces.com/contest/579/problem/D


整数N,K,XそしてN個の整数Aが与えられる。
N個の整数Aのうち、一つの整数A[i](1<= i <= N)にXをK回かける。
そして残りのN-1個の整数とA[i]をOR演算した場合の最大値を求める。

解法

全探索だと間に合わなかったので、A[0]からA[N - 1]までとA[N - 1]からA[0]までの部分和の計算結果ごとに配列に記録していった。

例えば、問題ページの2つ目のサンプルケースの場合を考えると、
N = 4, K = 2 ,X = 3で、A = { 1, 2, 4, 8 }なので 添え字が0からNまでの部分和の配列をsumAとすると、
sumA[0] = 0として、
sumA[1] = sumA[0] OR A[0] (1 = 0 OR 1)
sumA[2] = sumA[1] OR A[1] (3 = 1 OR 2)
sumA[3] = sumA[2] OR A[2] (7 = 3 OR 4)
sumA[4] = sumA[3] OR A[3] (15 = 7 OR 8)
という風にしていき、逆方向からも部分和を求めていく。
逆方向から部分和を求める配列をsumBとすると、
sumB[4] = 0として、
sumB[3] = sumB[4] OR A[3] (8 = 0 OR 8)
sumB[2] = sumB[3] OR A[2] (12 = 8 OR 4)
sumB[1] = sumB[2] OR A[1] (14 = 12 OR 2)
sumB[0] = sumB[1] OR A[0] (15 = 14 OR 1)

そして、A[i]を K回 Xをかけた値と部分和の計算結果を使って最大値を求める。

ソースコード

import java.util.Scanner;
public class D
{
	public void solve()
	{
		Scanner cin = new Scanner(System.in);
		int N = cin.nextInt();
		int K = cin.nextInt();
		int x = cin.nextInt();
		int[] a = new int[N];
		long[] b = new long[N];
		long[] sumA = new long[N + 1];
		long[] sumB = new long[N + 1];
		for(int i = 0;i < N;i++)
		{
			int j = cin.nextInt();
			a[i] = j;
			b[i] = j;
		}

		for(int i = 0;i < N;i++)
		{
			sumA[i + 1] = sumA[i] | a[i];
		}

		for(int i = N - 1;i >= 0;i--)
		{
			sumB[i] = sumB[i + 1] | a[i];
		}
		long ans = 0;
		for(int i = 0;i < N;i++)
		{
			for(int j = 0;j < K;j++)
			{
				b[i] *= x;
			}

			long max = sumA[i] | b[i] | sumB[i + 1];
			ans = Math.max(ans,max);
		}
		System.out.println(ans);
	}
	public static void main(String[] args) 
	{
		new D().solve();	
	}
}