牛客练习赛29 算式子

链接:https://www.nowcoder.com/acm/contest/211/F
来源:牛客网

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

给定  个整数  。保证 
对于每个  ,求出 。为了避免过量输出,你只需要将所有的 m 个结果异或起来输出。

输入描述:

第一行两个整数  。
第二行  个整数,第  个表示  。

输出描述:

一行一个整数,表示所有结果异或起来的结果。
示例1

输入

复制
2 2
1 2

输出

复制
0

说明

当 
x=1 \
 时,结果为 
4\


当 
x=2 \
时,结果为  
4\
 。

所以输出 
0 \
示例2

输入

复制
10 10
1 3 5 5 2 5 9 3 1 10

输出

复制
60

备注:

 
 
 
赛后看了很久旺神的代码,终于看懂了这道题。
分析:首先我们需要处理两种情况,x在上面和x在下面的情况
           当x在上面时,我们需要记录(1-m)的每个位置产生的贡献,对于当前位置x的贡献,等于它是多少个a[i]的倍数,我们可以将这个倍数关系,进行预处理的向上累加,如果:a[1]=1,a[2]=2,那么我们用cnt[i]表示a数组中i的个数,那么cnt[2]=1,cnt[1]=1,如果我们将倍数累加上去,cnt[2]=2,cnt[1]=1,也就是说在1这个位置产生的贡献为1,在2这个位置产生的贡献为2,当x=2时,我们累加1和2位置的贡献即可,结果为3 ,那么当x为k的时候,我们同样累加1-k的贡献即可,处理的时候可以用前缀和进行处理。
           当x在下面的时候,我们需要找每个ai产生的贡献,对于一个ai,它的贡献可以这样看,设定一个suma数组,让1-ai的值为1,那么当我们跑x的时候,累加上对应的suma[kx]的值即可,比如当前x的值为2,ai为8,那么处理为让suma的下标为1-8的位置+1,
当前贡献等于suma[x]+suma[2x]+suma[3x]+suma[4x]. 这样的话,我们就可以先跑所有的ai值,处理出最后的suma数组,然后在跑x,并不断累加对应的suma[kx]的值
 
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const int MAXN=2e6+100;
LL a[MAXN];
LL cnt[MAXN];
LL sumb[MAXN];
LL suma[MAXN];
LL n,m,x;
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
    {
      scanf("%lld",&a[i]);
      suma[1]++;
      suma[a[i]+1]--;
      cnt[a[i]]++;
    }

    for(int i=1;i<=m;i++)
    suma[i]+=suma[i-1];

    for(int i=m;i>=1;i--)
    {
       for(int k=i+i;k<=m;k+=i)
       cnt[k]+=cnt[i];
    }
    for(int i=1;i<=m;i++)
    {
     sumb[i]=sumb[i-1]+cnt[i];
    }


    LL up_x=0;
    LL down_x=0;
    LL ans=0;
    for(int i=1;i<=m;i++)
    {
       down_x=0;
       for(int j=i;j<=m;j+=i)
       down_x+=suma[j];
       up_x=sumb[i];
       ans^=(down_x+up_x);
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-10-20 11:11  hinata_hajime  阅读(238)  评论(0编辑  收藏  举报