XOR Segment (动态规划||苏州大学计算机学院三月月赛暨蓝桥杯热身赛)

XOR Segment

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 39   Accepted Submission(s) : 13

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

  给出 n 个数的数列,让你求出异或和为零的连续子段,如果有多个答案,要求连续字段长度最短,如果长度最短子段有多个,取最靠前的字段。
  异或操作体现在C++里面:^操作,两数做异或的含义是其对应的每一位二进制位做异或,例如:5 ^ 7 = (101) ^ (111) = (010) = 2

Input

第一行一个数据组数 T,(T <= 100)
每组数据第一行一个 n(n <= 10^6)
第二行给出 n 个数,0 <= 数值 < 10^5

Output

每组数据输出一行子段的左右端点,如果不存在这样的字段,输出-1

Sample Input

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

Sample Output

1 3
-1
2 2

Author

Natureal
Statistic | Submit | Back

这道题 做了好久   用了好多方法

第一次没有考虑n的范围 就直接用o(n*n)的时间复杂度做的 而且还不知道可以直接用异或符号^ 自己定义的 结果TLE

然后又用的线段树 发现少考虑情况了 如果加上少考虑的情况 进行n*n此查找 肯定会超时  就提前结束了

最后想的要么是贪心 要么是dp 贪心自己真的不知道如何贪心 于是就用了dp

dp数组分别为 t个数的异或的和 

使用t++ 更新异或和的个数

看代码吧

#include <stdio.h>
#include <string.h>
int a[1000000+5];
int dp[1000000+5];
int main()
{
	int ncase;
	scanf("%d",&ncase);
	while(ncase--)
	{
		memset(a,0,sizeof(a));
		memset(dp,0,sizeof(dp));
		int n,flag=-1;
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			dp[i]=a[i];
			if(dp[i]==0&&flag==-1)
			flag=i;
		}
		if(flag!=-1)
		{
			printf("%d %d\n",flag+1,flag+1);
			continue;
		}
		int right=-1,left=0,t=0;
		while(right-left==-1)
		{
			t++;
			if(t>n)
			break;
			for(int i=0;i<n;i++)
			{
				if(i+t<n)
				{
					dp[i]=dp[i]^a[i+t];	
					if(dp[i]==0)
					{
						right=i+t;
						left=i;
						break;
					}
					
				}
				else
				break;
			}
		}
		if(right-left==-1)
		printf("-1\n");
		else
		printf("%d %d\n",left+1,right+1);
	}
}


你可能感兴趣的:(动态规划,异或段)