【模拟赛】【DP】2021.8.9.A

30 篇文章 0 订阅

题目描述

给出一个数组,求每两个相邻的数进行操作n-1次后所有可能得出的数
操作如下
a ( x ) b = ( ( a   &   b ) + ( a   ∣   b ) ) > > 1 a(x)b= ((a\ \&\ b) + (a\ |\ b))>>1 a(x)b=((a & b)+(a  b))>>1

样例输入

4
1 4 3 2

样例输出

1 2

思路

因为 a   &   b   =   m i n ( a ,   b ) a\ \&\ b\ =\ min(a,\ b) a & b = min(a, b) a   ∣   b   =   m a x ( a ,   b ) a\ |\ b\ =\ max(a,\ b) a  b = max(a, b)
所以 ( ( a   &   b ) + ( a   ∣   b ) )   > >   1 = ( a   +   b )   > >   1 ((a\ \&\ b) + (a\ |\ b))\ >>\ 1 = (a\ +\ b)\ >>\ 1 ((a & b)+(a  b)) >> 1=(a + b) >> 1

DP
f i , j , k f_{i,j,k} fi,j,k为合并 i , j i, j i,j区间,最终结果为 k k k 0 / 1 0/1 0/1状态
因为数据给出 a i   ⩽   7 a_i\ \leqslant\ 7 ai  7,所以平均值也小于等于7
所以状态只有0~7
看转移
枚举长度 l e n len len,左端点 l l l,则右端点 r = l + l e n − 1 r = l + len - 1 r=l+len1
枚举分割点 k k k,左区间的值 q q q,右区间的值 p p p
f l , r , ( p + q ) > > 1 = f l , k , q   &   f k + 1 , r , p f_{l, r, (p + q) >> 1} = f_{l, k, q}\ \&\ f_{k + 1, r, p} fl,r,(p+q)>>1=fl,k,q & fk+1,r,p
时间复杂度 O ( n 3   ∗   8 2 ) O(n ^ 3 \ * \ 8 ^ 2) O(n3  82)
时间复杂度应该是可以刚好过

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

int A[2005], F[155][155][10];
int n, Maxx;

int main()
{
	memset(F, 0, sizeof(F));
	scanf("%d", &n);
	Maxx = -1e9;
	for(int i = 1; i <= n; ++i)
	{
		scanf("%d", &A[i]);
		Maxx = max(Maxx, A[i]);
		F[i][i][A[i]] = 1;
	}
	for(int k = 1; k <= n; ++k)
		for(int i = 1; i <= n; ++i)
		{
			int j = i + k - 1;
			for(int l = i; l < j; ++l)
				for(int p = 0; p <= Maxx; p++)
					for(int q = 0; q <= Maxx; q++)
						if(F[i][l][p] && F[l + 1][j][q])
							F[i][j][(p + q) >> 1] = 1;
		}
	for(int i = 0; i <= Maxx; ++i)
		if(F[1][n][i])printf("%d ", i);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值