牛客练习赛29 算式子
链接:https://www.nowcoder.com/acm/contest/211/F
来源:牛客网
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给定 个整数 。保证 。
对于每个 ,求出 。为了避免过量输出,你只需要将所有的 m 个结果异或起来输出。
输入描述:
第一行两个整数 。
第二行 个整数,第 个表示 。
输出描述:
一行一个整数,表示所有结果异或起来的结果。
备注:
赛后看了很久旺神的代码,终于看懂了这道题。
分析:首先我们需要处理两种情况,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; }