1. 程式人生 > >JZOJ5935. 【NOIP2018模擬10.29】小凱學數學

JZOJ5935. 【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

題解

先分析一下題目給出的運算,
a $ b =( (a&b) + (a|b) )>>1
觀察二進位制位置上面,就是一個交集再加上一個並集,其實就是a+b嘛,
所以呢,這個東西就是(a+b)/2 。
知道了這個性質,出來起來就比較方便了,
f

i , j , k f_{i,j,k} 表示從i到j這一段,是否最終是否可以變為一個數k,
轉移就先列舉一個區間[i,j],然後列舉一個分界點,將一個區間分成兩個區間,
最後再列舉這兩個區間最終是什麼數字。

code

#include <cstdio>
#include <iostream>
#include <cstring>
#define N 153
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
	n=0;
	ch=G();
	while((ch<'0' || ch>'9') && ch!='-')ch=G();
	int w=1;
	if(ch=='-')w=-1,ch=G();
	while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
	n*=w;
}

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

int main()
{
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	
	memset(f,0,sizeof(f));
	read(n);
	for(int i=1;i<=n;i++)read(x),f[x][i][i]=1;
	
	for(int l=2;l<=n;l++)
		for(int i=1;i+l-1<=n;i++)
			for(int j=i+1;j<=n;j++)
				for(int p1=0;p1<8;p1++)
					for(int p2=0;p2<8;p2++)
						f[(p1+p2)>>1][i][l+i-1]|=f[p1][i][j-1]&&f[p2][j][i+l-1];
	for(int i=0;i<8;i++)
		if(f[i][1][n])P(i+48),P(' ');
	
	return 0;
}