链接:https://www.nowcoder.com/acm/contest/211/F
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给定
n
n
n个整数
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an 。保证
1
≤
a
i
≤
m
1\le a_i\le m
1≤ai≤m 。
对于每个
1
≤
x
≤
m
1\le x\le m
1≤x≤m,求出
∑
i
=
1
n
(
⌊
a
i
x
⌋
+
⌊
x
a
i
⌋
)
\sum_{i=1}^{n}(\lfloor \frac{a_i}{x} \rfloor+\lfloor \frac{x}{a_i}\rfloor)
∑i=1n(⌊xai⌋+⌊aix⌋)。为了避免过量输出,你只需要将所有的 m 个结果异或起来输出。
输入描述:
第一行两个整数n,m。
第二行n个整数,第i个表示
a
i
a_i
ai。
输出描述:
一行一个整数,表示所有结果异或起来的结果。
示例1
输入
2 2
1 2
输出
0
示例2
输入
10 10
1 3 5 5 2 5 9 3 1 10
输出
60
备注:
1
≤
n
,
m
≤
2
×
1
0
6
1\le n,m\le2\times10^6
1≤n,m≤2×106 ,
1
≤
a
i
≤
m
1\le a_i\le m
1≤ai≤m
思路:对于 ⌊ a i x ⌋ \lfloor \frac{a_i}{x} \rfloor ⌊xai⌋,枚举分母x以及x的倍数,其中位于 [ k ∗ x , ( k + 1 ) ∗ x ) [k*x,(k+1)*x) [k∗x,(k+1)∗x)里的数除以x的值都是k,所以可以统计 a i a_i ai的值在这个区间里的个数,然后加入到x的答案里。
对于 ⌊ x a i ⌋ \lfloor \frac{x}{a_i} \rfloor ⌊aix⌋,同理,枚举分母及其倍数,其中位于区间 [ k ∗ i , ( k + 1 ) ∗ i ) [k*i,(k+1)*i) [k∗i,(k+1)∗i)里的x的答案都会加上 a i a_i ai的值在这个区间里的个数*k。
复杂度= O ( m + m 2 + m 3 + . . . + m m ) ≈ O ( m l o g m ) O(m+\frac m2+\frac m3+...+\frac mm)\approx O(mlogm) O(m+2m+3m+...+mm)≈O(mlogm)
#include<bits/stdc++.h>
using namespace std;
const int MAX=4e6+10;
typedef long long ll;
ll ans[MAX];
int a[MAX],cnt[MAX];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
cnt[a[i]]++;
}
for(int i=1;i<=m;i++)
{
for(int j=i;j<=m;j+=i)
{
ans[j]+=1ll*j/i*cnt[i];
ans[j+i]-=1ll*j/i*cnt[i];
}
}
for(int i=1;i<=m;i++)ans[i]+=ans[i-1];
for(int i=1;i<=2*m;i++)cnt[i]+=cnt[i-1];
for(int i=1;i<=m;i++)
{
for(int j=i;j<=m;j+=i)ans[i]+=1ll*j/i*(cnt[j+i-1]-cnt[j-1]);
}
ll sum=0;
for(int i=1;i<=m;i++)sum^=ans[i];
cout<<sum<<endl;
return 0;
}