2018 FJUT ACM校赛 B题 第二集:以后我就叫你小蛤了
第二集:以后我就叫你小蛤了
TimeLimit:1000MS MemoryLimit:128MB
64-bit integer IO format:%lld
Problem Description
"小蛤啊,对了以后我就叫你小蛤了,你给的题完全没有难度啊"
"哼,你别得意,让你碰巧做出来了而已,接下来这题你绝对不可能做出来的,你要是做出来了balabalabala...."
"行了行了,快说题目吧,我时间宝贵啊!" 小A心急如焚,想尽快知道小C的消息
"请听题:
给n个正整数a1,a2,a3,……,an,求所有子区间异或和的异或和。比如{2,4,6}的子区间有{{2},{4},{6},{2,4},{4,6},{2,4,6}}
其中异或是按位异或,即C/C++中的"^"运算符"
"这么简单,看我三下五除二解决了这题,三分钟后你就叫小蛤没得商量了!你答应给我,告诉我小C的消息可不许反悔!"
"哼,爷蛤蟆大仙是那种会反悔的人吗,而且你不可能会做这题的,看你一会怎么给自己找台阶下!"
注意异或有两个常用的性质(下面的"^"代表异或运算)
-
a^a=0
-
a^0=a
Input
单组数据
开头是一个整数n代表n个数字,n<=5*105
接下来有n个数a1,a2,a3,……an ,(0<=ai<230)
Output
输出所有子区间异或和的异或和
SampleInput
4 3 3 6 7
SampleOutput
0
hint: 所有子区间与对应的异或和如下: {3} 3 {3,3} 0 {3,3,6} 6 {3,3,6,7} 1 {3} 3 {3,6} 5 {3,6,7} 2 {6} 6 {6,7} 1 {7} 7 所以答案=3^0^6^1^3^5^2^6^1^7=0
【思路】:
你可以发现一个规律,第一个位置的数出现的次数为n,第二个位置的数出现的次数为2*(n-1)....到中间位置
比如
1 2 3
3 4 3
1 2 3 4
4 6 6 4
1 2 3 4 5
5 8 9 8 5
红色为单个位置上的出现个数
然后两边对称,我的思路是先把每个位置的次数打个表。再根据题意给的
-
a^a=0
-
a^0=a
因为如果在这个位置的次数为奇数 的话,肯定等于它本身。
为偶数,肯定等于0
进行有运算后保存,最后再进行一次O(n)的求和。
就可以得到答案了。
贴上代码(运行时间:40ms)
#include<cstdio> #include<cstring> #include<iostream> using namespace std; typedef long long ll; ll math[500005]; ll data[500005]; int main() { int n; while(~scanf("%d",&n)) {memset(math,0,sizeof(math)); ll a; ll c=n; ll b=1; int flag=0; if(n%2==0) { a=n/2; } else {a=n/2+1; flag=1; } for(int i=0;i<a;i++) { math[i]=c*(b); b++; c--; } int j; if(flag==0) j=a-1; else j=a-2; for(int i=a;i<n;i++) { math[i]=math[j]; j--; } for(int i=0;i<n;i++) {scanf("%lld",&data[i]); if(math[i]%2==0) data[i]=0; } ll sum=0; for(int i=0;i<n;i++) { sum^=data[i]; } printf("%lld\n",sum); } return 0; }