1. 程式人生 > >jzoj5935. 【NOIP2018模擬10.29】小凱學數學(區間dp)

jzoj5935. 【NOIP2018模擬10.29】小凱學數學(區間dp)

5935. 【NOIP2018模擬10.29】小凱學數學

Description
由於小凱上次在找零問題上的疑惑,給大家在考場上帶來了很大的麻煩,他決心好好學習數學
本次他挑選了位運算專題進行研究 他發明了一種叫做“小凱運算”的運算子:
a$b =( (a&b) + (a|b) )>>1
他為了練習,寫了n個數在黑板上(記為a[i]) 並對任意相鄰兩個數進行“小凱運算”,把兩數擦去,把結果留下 這樣操作n-1次之後就只剩了1個數,求這個數可能是什麼?
將答案從小到大順序輸出

Input
4
1 4 3 2

Output
1 2

Sample Input
4
1 4 3 2

Sample Output
1 2

Data Constraint
​ 30% n<=10 0<=a[i]<=7
70% n<=150 0<=a[i]<=3
100% n<=150 0<=a[i]<=7

分析:只要利用運算的有界性即可 進行區間 dp f[i][j][k]代表 i 到 j 的區間是否可能結果為 k 轉移易知

程式碼

#include <cstdio>
#define N 155
using namespace std;

bool f[N][N][8];
int n,a[N];

int main()
{
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	scanf("%d", &n);
	int mx = 0;
	for (int i = 1; i <= n; i++) 
	{
		scanf("%d", &a[i]);
		f[i][i][a[i]] = true;
		if (a[i] > mx) mx = a[i];
	}
	for (int i = n; i >= 1; i--)
		for (int j = i + 1 ; j <= n; j++)
			for (int k = i; k <= j; k++)
				for (int x = 0; x <= mx; x++)
					for (int y = 0; y <= mx; y++)
						f[i][j][(x + y) / 2] = f[i][j][(x + y) / 2] | (f[i][k][x] & f[k + 1][j][y]);
	for (int i = 0; i <= mx; i++)
		if (f[1][n][i]) printf("%d ", i);
}