zoukankan      html  css  js  c++  java
  • NOI.AC CSP-S全国模拟赛第四场 子段与子段

    题目描述

    对于一个序列a1,a2,…,an,子段是指它的一个连续部分,即al,al+1,…,ar
    容易发现,一个长度为n的序列有$frac{n(n+1)}{2} $
    个子段。例如序列3,7,4有下列子段:

    (3),(3,7),(3,7,4),(7),(7,4),(4)

    Mia希望分别求出这些子段的异或和,再将它们异或起来。但是Cierra觉得这太简单了,所以她提出了q个询问,每次给出一个区间[L,R],希望你将这个下标区间对应的子段截取出来,回答上面的询问。

    具体来说,对询问[L,R],你需要回答aL,aL+1,…,aR的所有子段异或和的异或和。

    输入格式

    第一行包含两个用空格隔开的整数n,q
    第二行包含n个用空格隔开的整数a1,a2,…,an
    之后q行,每行包含两个用空格隔开的整数L,R,依次代表q组询问

    输出格式

    对每个询问输出一行,包含一个整数,为该区间所有子段异或和的异或和

    样例输入

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

    样例输出

    2
    6
    0
    

    数据限制

    对于30%的数据,n,q≤500

    对于60%的数据,n,q≤5000

    对于100%的数据,1≤n,q≤200000,0≤ai≤109,每一组L,R均满足1≤L≤R≤n

    时空限制

    1000ms, 512MB

    推式子的题目

    我们这里用(sum)表示区间异或(即用^代替+)。

    题目让我们求的是(sum_{i=l}^{r} sum_{j=i}^{r} sum_{k=i}^{j}a_i).

    首先我们先预处理一下前缀亦或和(s[]),那么就是(sum_{i=l}^{r} sum_{j=i}^{r} s_{j}) ^ (s_{i-1}),发现(s_{i-1})(j)无关,我们提出来之后就是

    ( sum_{i=l}^{r} s_{i-1} imes) ( (r - i + 1 )&1) ^
    (sum_{j=i}^{r} s_{j})

    我们再对s[]数组做一次前缀和设为t[],进一步就能把式子化为
    ( sum_{i=l}^{r} s_{i-1} imes) ( (r - i + 1 )&1) ^
    $ t_{r}$ ^ (t_{i-1})

    这时就有了60分了。

    我们发现前半部分s的取与不取和(r-i+1)的奇偶性有关,我们分别做一下前缀和,后半部分对(t)做一个前缀和就行了。

    while (m--) 
    {
       l = read(); r = read(); ans = 0;
       if ((r - l + 1) & 1)ans = t[r];
       else ans = 0;
    
       ans ^= (p[r - 1] ^ p[l - 2]);
    
       if (!(r & 1))ans ^= ji[r - 1] ^ ji[max(l - 2, 0)];
       else ans ^= ou[r - 1] ^ ou[max(l - 2, 0)];
       printf("%d
    ", ans);
    }
    

    这样每次就能做到(O(1))询问了。

    最后献上我丑陋的代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int n, m, l, r, ans;
    const int N = 200010;
    int a[N], s[N], t[N], p[N], ji[N], ou[N];
    inline int read() 
    {
    	int res = 0; char ch = getchar(); bool XX = false;
    	for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    	for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    	return XX ? -res : res;
    }
    int main() 
    {
    	cin >> n >> m;
    	for (int i = 1; i <= n; ++i)a[i] = read();
    	for (int i = 1; i <= n; ++i)s[i] = a[i] ^ s[i - 1];
    	for (int i = 1; i <= n; ++i)t[i] = s[i] ^ t[i - 1];
    	for (int i = 1; i <= n; ++i)p[i] = t[i] ^ p[i - 1];
    
    	for (int i = 1; i <= n; ++i)
    		if (i & 1)ji[i] = ji[i - 1] ^ s[i];
    		else ji[i] = ji[i - 1];
    	
    	for (int i = 1; i <= n; ++i)
    		if (!(i & 1))ou[i] = ou[i - 1] ^ s[i];
    		else ou[i] = ou[i - 1];
    	
    	while (m--) 
    	{
    		l = read(); r = read(); ans = 0;
    		if ((r - l + 1) & 1)ans = t[r];
    		else ans = 0;
    
    		ans ^= (p[r - 1] ^ p[l - 2]);
    
    		if (!(r & 1))ans ^= ji[r - 1] ^ ji[max(l - 2, 0)];
    		else ans ^= ou[r - 1] ^ ou[max(l - 2, 0)];
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    iOS layoutSubviews 什么时候会被调用
    view
    NSDictionaryOfVariableBindings
    获取相册中得图片
    相机
    给定文字测量它的大小
    git
    单例的创建
    物理引擎简介——Cocos2d-x学习历程(十三)
    场景切换特效Transition——Cocos2d-x学习历程(十二)
  • 原文地址:https://www.cnblogs.com/wljss/p/11701162.html
Copyright © 2011-2022 走看看