RDay1-Problem 3 C
题目描述
初始给定n个卡片拍成一排,其中第i个卡片上的数为x[i]。
有q个询问,每次询问给定L和R表示询问区间[L,R]内的卡片所有出现了偶数次的数的异或和是多少。
输入
输入文件C.in
输入一行两个整数n,q。
第二行n个整数,第i个数为x[i]。
接下来q行,每行两个整数L和R,表示询问的区间。
输出
输出文件C.out
输出q行,其中第i行表示第i次询问的区间出现偶数次的数的异或和。
样例输入
3 1
3 7 8
1 3
样例输出
0
【样例输入2】
7 5
1 2 1 3 3 2 3
4 7
4 5
1 3
1 7
1 5
【样例输出2】
0
3
1
3
2
【数据范围】
对于20%的数据,$ n , q \le 10^3 $
对于另外20%的数据,$ n , q \le 5 \times 10^4 , a_i \le 10 $
对于100%的数据, $ n , q \le 10^6 , 0 \le a[i] \le 10^9 $
这道毒瘤题.....我->TM->根本->不会
但是我会四十分啊.......
四十分就很简单了,首先,对于前 $ 20 % $ 的数据,直接暴力模拟即可,毫无难度可言
另外 $ 20 % $ 的数据,需要稍微动一点脑子,因为它具有特殊性质:$ a_i \le 10 $
所以可以在前缀和的基础上加一维来作为桶统计出现次数,然后就是判断了,也很简单
虽然写的是40分,但是我得了45分,也算是意外惊喜吧.
四十分代码如下:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define max(a,b) (a > b ? a : b)
#define Noip2018RpINF return 0
const int N = 5e4 + 5 ;
int n,v[N],q,tra[N],maxi,ans;
int sum_ap[N][15];
inline int read(){
int x = 0 , f = 1 ;char ch = getchar ();
while ( ch < '0' || ch > '9' ){if ( ch == '-' ) f = - 1 ;ch = getchar () ;}
while ( ch >= '0' && ch <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( ch ^ 48 ) ;ch = getchar ();}
return f * x ;
}
int main(){
n = read () , q = read() ;
for (int i = 1 ; i <= n ; ++ i) v[i] = read () , maxi = max (maxi , v[i]) ;
if ( n <= 2000 ){
while (q--){
register int l = read () , r = read () ;
memset( tra , false , sizeof (tra) );maxi = - 1 ; ans = 0 ;
for (int i = l ; i <= r ; ++ i) ++ tra[ v [ i ] ] , maxi = max (maxi , v[i]);
for (int i = 1 ; i <= maxi ; ++i){
if( ( tra[i] & 1 ) || ! tra[i] ) continue ;
ans ^= i ;
}
printf("%d\n" , ans);
}
}else if(n <= 50000){
sum_ap[1][v[1]] = 1 ;
for (int i = 2 ; i <= n ; ++ i)
for(int j = 0 ; j <= maxi ; ++ j)
if( v[i] == j ) sum_ap[i][j] = sum_ap[i - 1][j] + 1 ;
else sum_ap[i][j] = sum_ap[i - 1][j] ;
while (q--){
register int l = read () , r = read (); ans = 0 ;
for(int i = 1 ; i <= maxi ;++ i){
if( ! ( (sum_ap[r][i] - sum_ap[ l - 1 ][i]) & 1 ) && (sum_ap[r][i] - sum_ap[ l - 1 ][i]) )
ans ^= i ;
}
printf ("%d\n" , ans);
}
}
Noip2018RpINF;
}
通过我校 $ rjx 大佬 $ 的讲解,我成功学会了这道题的正解:树状数组+前缀异或和
有一点点前置知识: $ a \bigoplus b = c $ 则 $ a = b \bigoplus c $
我们用 $ a $ 表示区间内出现偶数次的数的异或和,用 $ b $ 表示区间内出现了奇数次的数的异或和,用 $ c $ 表示整个区间所有数字的异或和(每个数字只计算一次)
那么,根据上面的性质,我们可以得到如下结论:
$ a = b \bigoplus c $
所以我们就考虑维护区间内出现奇数次的数的异或和以及整个区间所有不同的数字的异或和
区间内出现奇数次的数的异或和显然可以使用前缀异或和来维护
那么整个区间内所有不同的数的异或和呢?
这里我们采用树状数组维护,开一个数组 $ pre_i $ 表示在 $ i $ 这个位置之前的最靠近 $ v_i $ 的数的位置
另一个 $ map $ 表示 $ v_i $ 的下标,用来辅助构建 $ pre $ 数组
然后,我们把所有的询问区间离线,按右端点升序排序,按升序排序的原因是我们从左向右推,这样可以避免推完之后再回去推一遍,从而保证单纯推的过程复杂度保持在 \(\Theta(n)\)
之后,在向右推进的过程中,我们每遇到一个数,如果它没有前缀(即第一次出现,它对应的 $ pre $ 数组为空),那么就直接加入树状数组
否则,现在树状数组中删除它的前缀,再把它加进去,这样,显然我们可以保证最后树状数组中有且仅有每个数字一个,最后我们查询树状数组,再把查询结果异或整段区间的异或和(即出现了奇数次的异或和)就得到该次询问的答案
代码如下:
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <map>
#define lowbit(x) ( - x & x )
using std::map;
const int N = 1e6 + 5 ;
struct querys{
int left , right , dir ;
}qs[N];
int n,q,v[N],pre[N];
int ans[N],t[N],sum[N];
map < int , int > vis ;
inline void update(int dir , int val){
while(dir <= n){
t[dir] ^= val ;
dir += lowbit(dir);
}
return ;
}
inline int query(int dir){
register int res = 0 ;
while(dir){
res ^= t[dir] ;
dir -= lowbit(dir);
}
return res;
}
inline bool cmp(const querys & a ,const querys & b ){return a.right < b.right ;}
int main(){
scanf("%d%d" , & n , & q );
for (int i = 1 ; i <= n ; ++ i){
scanf("%d" , & v[i] );
sum[i] = sum[i - 1] ^ v[i] ;
pre[i] = vis[ v[i] ] ; vis[ v[i] ] = i ;
}
for (int i = 1 ; i <= q ; ++ i)
scanf("%d%d" , & qs[i].left , & qs[i].right ) , qs[i].dir = i ;
std::sort( qs + 1 , qs + q + 1 , cmp );
register int now = 1 ;
for (int i = 1 ; i <= q ; ++ i){
while(now <= qs[i].right){
if( pre[now] ) update( pre[now] , v[now] );
update( now , v[now] ); ++ now ;
}
ans[qs[i].dir] = query( qs[i].right ) ^ query( qs[i].left - 1 ) ^ sum[ qs[i].right ] ^ sum[ qs[i].left - 1 ] ;
}
for (int i = 1 ; i <= q ; ++ i) printf("%d\n" , ans[i]);
return 0;
}
RDay1-Problem 3 C的更多相关文章
- 1199 Problem B: 大小关系
求有限集传递闭包的 Floyd Warshall 算法(矩阵实现) 其实就三重循环.zzuoj 1199 题 链接 http://acm.zzu.edu.cn:8000/problem.php?id= ...
- No-args constructor for class X does not exist. Register an InstanceCreator with Gson for this type to fix this problem.
Gson解析JSON字符串时出现了下面的错误: No-args constructor for class X does not exist. Register an InstanceCreator ...
- C - NP-Hard Problem(二分图判定-染色法)
C - NP-Hard Problem Crawling in process... Crawling failed Time Limit:2000MS Memory Limit:262144 ...
- Time Consume Problem
I joined the NodeJS online Course three weeks ago, but now I'm late about 2 weeks. I pay the codesch ...
- Programming Contest Problem Types
Programming Contest Problem Types Hal Burch conducted an analysis over spring break of 1999 and ...
- hdu1032 Train Problem II (卡特兰数)
题意: 给你一个数n,表示有n辆火车,编号从1到n,入站,问你有多少种出站的可能. (题于文末) 知识点: ps:百度百科的卡特兰数讲的不错,注意看其参考的博客. 卡特兰数(Catalan):前 ...
- BZOJ2301: [HAOI2011]Problem b[莫比乌斯反演 容斥原理]【学习笔记】
2301: [HAOI2011]Problem b Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 4032 Solved: 1817[Submit] ...
- [LeetCode] Water and Jug Problem 水罐问题
You are given two jugs with capacities x and y litres. There is an infinite amount of water supply a ...
- [LeetCode] The Skyline Problem 天际线问题
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
- PHP curl报错“Problem (2) in the Chunked-Encoded data”解决方案
$s = curl_init(); curl_setopt($s, CURLOPT_POST, true); curl_setopt($s, CURLOPT_POSTFIELDS, $queryStr ...
随机推荐
- 利用CocoaHttpServer搭建手机本地服务器
原理 使用CocoaHTTPServer框架,在iOS端建立一个本地服务器,只要电脑和手机连入同一热点或者说网络,就可以实现通过电脑浏览器访问iOS服务器的页面,利用POST实现文件的上传. 实现 1 ...
- 算法笔记-状压dp
状压dp 就是把状态压缩的dp 这样还是一种暴力但相对于纯暴力还是优雅的多. 实际上dp就是经过优化的暴力罢了 首先要了解位运算 给个链接吧 [https://blog.csdn.net/u01337 ...
- nginx 编译参数详解(运维必看--转)
nginx参数: –prefix= 指向安装目录 –sbin-path 指向(执行)程序文件(nginx) –conf-path= 指向配置文件(nginx.conf) –error-log-path ...
- Android艺术——Bitmap高效加载和缓存代码分析(2)
Bitmap的加载与缓存代码分析: 图片的压缩 比如有一张1024*768像素的图像要被载入内存,然而最终你要用到的图片大小其实只有128*96,那么我们会浪费很大一部分内存,这显然是没有必要的,下面 ...
- A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse.
cp -r /home/cuthead/android-studio/jre /home/cuthead/adt-bundle-linux-x86_64-20131030/eclipse/jre 使用 ...
- UVA 10618 Tango Tango Insurrection
https://vjudge.net/problem/UVA-10618 题目 你想学着玩跳舞机.跳舞机的踏板上有4个箭头:上.下.左.右.当舞曲开始时,屏幕上会有一些箭头往上移动.当向上移动箭头与顶 ...
- Kali Linux 发布 2019.1 版
Kali Linux 是一个基于 Debian 的发行版,关注于高级渗透测试和安全审计并搭载各种常用工具,由 Offensive Security 维护.后者是一个提供信息安全训练的公司. 该项目于日 ...
- Python future使用
Python的每个新版本都会增加一些新的功能,或者对原来的功能作一些改动.有些改动是不兼容旧版本的,也就是在当前版本运行正常的代码,到下一个版本运行就可能不正常了. 从Python 2.7到Pytho ...
- Go语言嵌入类型
一.什么是嵌入类型 先看如下代码: type user struct { name string email string } type admin struct { user // Embedded ...
- 将服务器文件上传到ftp shell操作
date cd /home/data today_now=`date +%Y%m%d` #当前日期 cur_date=${today_now::} #echo ${cur_date} #判断是否文件生 ...