关于练习题(HDU5968,HDU5969)

problem H:异或密码

晨晨在纸上写了一个长度为N的非负整数序列{aiai}。对于这个序列的一个连续子序列{al,al+1,…,aral,al+1,…,ar}晨晨可以求出其中所有数异或的结果 al xor al+1xor…xor ar其 中xor表示位异或运算,对应C、C++、 Java等语言中的^运算。
小璐提出了M个询问,每个询问用一个整数 xixi描述。
对于每个询问,晨晨需要找到序列{ai}的所有连续子序列,求出每个子序列异或的结果,找到所有的结果中与 xi之差的绝对值最小的一个,并告诉小璐相应子序列的长度。
若有多个满足条件的连续子序列,则告诉小璐这些子序列中最长的长度。
Input
包含多组测试数据,第一行一个正整数T,表示数据组数。
每组数据共两行。
第一行包含N+1个非负整数。其中第一个数为N,表示序列的长度;接下来N 个数,依次描述序列{ aiai}中的每个数。
第二行包含M+1个整数。其中第一个数为M,表示询问的个数;接下来M个数 xixi,每个数对应题目描述中的一个询问。
保证 1 <= N <= 100,1 <= M <= 100,ai <= 1024,|xi| <= 1024,数据组数 <= 100。
Output
对于每组数据输出M + 1行。前M行对应晨晨M个询问的回答,第M + 1行为空行

Sample Input

2
2 1 1
2 0 2
3 1 2 4
3 10 5 1

Sample Output

2
1

3
2
1

本题就是找出所有的连续子序列,经推算可知有n*(n+1)/2个上升的子序列,可以得出要存储的数组的大小。又根据题意N的范围为一百,直接暴力求解即可。

AC代码如下:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
 
int a[105];
int b[105];
int sum[5055];
int len[5055];
int main()
{
	int n, m1;
	
	int t;
	cin >> t;
	while (t--)
	{
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		memset(sum, 0, sizeof(sum));
		memset(len, 0, sizeof(len));
		int x = 0;
		int m;
		cin >> n;
		for (int i = 0; i < n; i++)
		{
			cin >> a[i];
		}
		cin >> m1;
		for (int i = 0; i < m1; i++)
			cin >> b[i];
		for (int i = 0; i < n; i++)
		{
			m = 0;
			for (int j = i; j < n; j++)
			{
				m ^= a[j];
				sum[x] = m;//依次存储当前序列的异或值
				len[x] = j - i + 1;//下标相减加一即为长度(存储长度)
				x++;
			}
			
		}
	/*	for (int i = 0; i < x; i++)
		{
			cout << "*" << sum[i] << "*";
		}
		cout << endl;*/

		for (int i = 0; i < m1; i++)
		{
			int inf = 9999999, lena = 0;

			for (int j = 0; j <x; j++)
			{

				if (inf >= abs(b[i] - sum[j]))
				{

					if (inf == abs(b[i] - sum[j]))
					{

						lena = max(lena, len[j]);//如果值相等则返回最长的长度

					}
					else{

						inf = abs(b[i] - sum[j]);//否则的话改变inf的大小
						lena = len[j];//将长度改为当前长度
					}
				}
			}
			cout << lena << endl;
		}
		cout << endl;
	}
	return 0;
}

HDU5969 最大的位或:

B君和G君聊天的时候想到了如下的问题。
给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大。
其中|表示按位或,即C、 C++、 Java中的|运算。
Input
包含至多10001组测试数据。
第一行有一个正整数,表示数据的组数。
接下来每一行表示一组数据,包含两个整数l,r。
保证 0 <= l <= r <= 10^18。

Output
对于每组数据输出一行,表示最大的位或。

Sample Input

5
1 10
0 1
1023 1024
233 322

1000000000000000000 1000000000000000000

Sample Output

15
1
2047
511
1000000000000000000

本题思路:就是要求最大的位或我们可以从二进制角度出发,根据或运算的性质位与位进行比较如二进制:

101100111011

100110011101

从前往后找到第一个位互不相同的,再将其后面的位都化为一即为最大的位或,化简为如下形式:

ans:101111111111即为最后的答案。

AC代码如下有以下两种形式:

(依次化为二进制再一个一个比较(找到不同的再化为一),再将二进制化为十进制(相对麻烦))。

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
ll a[100];
ll b[100];
ll c[100];
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		memset(c, 0, sizeof(c));
		long long x, y;
		cin >> x >> y;
		if (x == y)
		{
			cout << y << endl;
			continue;
		}
		int l = 1;
		while (x)
		{
			a[l++] = x % 2;//xiaode

			x /= 2;
		}
		ll m = 1;
		while (y)
		{
			b[m++] = y % 2;//大的
			y /= 2;
		}

		for (int i = m - 1; i >l - 1; i--)
		{
				a[i] = 0;
		}

		/*for (int i = 1; i <= m - 1; i++)
			cout <<"*"<< b[i] << "*";*/
		ll i1;
		for (i1 = m - 1; i1 >= 1; i1--)
		{
			c[i1] = b[i1];
			if (a[i1] != b[i1])
			{
				c[i1] = 1;
				for (i1; i1 >= 1; i1--)
				{
					c[i1] = 1;
				}
				break;
			}
		}
		long long sum = c[1];
		for (ll j = 2; j <= m - 1; j++)
		{
			long long s1 = 1;
			for (ll i = 1; i <j; i++)
					s1*=2;
			sum += c[j] * s1;
		}

		cout << sum << endl;
	}

	return 0;
}

(long long有63位直接通过右移63位逐步开始找,直到找到了不相同的保存当前位数)

#include<iostream>
using namespace std;

int main()
	{
	 long long L, r;
	int t;
	cin >> t;
	while (t--)
	{
		cin >> L >> r;
		long long i = 63;
		while (i >=0 && (r >> i) == (L>> i))i--;//依次比较高位是否相同从最高位64位开始比较
		long long x = (((long long)1 << (i + 1)) - 1);//找到了右移i+1位再减个一相或就是最大值。
		cout << (r | x) << endl;
	}

	return 0;
}


发布了40 篇原创文章 · 获赞 10 · 访问量 2578

猜你喜欢

转载自blog.csdn.net/lsdstone/article/details/99242272