牛客练习赛29-F:算式子

链接: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 1aim
对于每个 1 ≤ x ≤ m 1\le x\le m 1xm,求出 ∑ 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 1n,m2×106 1 ≤ a i ≤ m 1\le a_i\le m 1aim

思路:对于 ⌊ a i x ⌋ \lfloor \frac{a_i}{x} \rfloor xai,枚举分母x以及x的倍数,其中位于 [ k ∗ x , ( k + 1 ) ∗ x ) [k*x,(k+1)*x) [kx,(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) [ki,(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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值