1. 程式人生 > >牛客練習賽29-F:算式子

牛客練習賽29-F:算式子

時間限制:C/C++ 2秒,其他語言4秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld
題目描述
給定 nn個整數a1,a2,...,ana_1,a_2,...,a_n 。保證1aim1\le a_i\le m
對於每個1xm1\le x\le m,求出 i=1n(aix+xai)\sum_{i=1}^{n}(\lfloor \frac{a_i}{x} \rfloor+\lfloor \frac{x}{a_i}\rfloor)

aix)。為了避免過量輸出,你只需要將所有的 m 個結果異或起來輸出。
輸入描述:
第一行兩個整數n,m。
第二行n個整數,第i個表示aia_i
輸出描述:
一行一個整數,表示所有結果異或起來的結果。
示例1
輸入
2 2
1 2
輸出
0
示例2
輸入
10 10
1 3 5 5 2 5 9 3 1 10
輸出
60
備註:1n,m2×1061\le n,m\le2\times10^61aim1\le a_i\le m

思路:對於aix\lfloor \frac{a_i}{x} \rfloor,列舉分母x以及x的倍數,其中位於[

kx,(k+1)x)[k*x,(k+1)*x)裡的數除以x的值都是k,所以可以統計aia_i的值在這個區間裡的個數,然後加入到x的答案裡。

對於xai\lfloor \frac{x}{a_i} \rfloor,同理,列舉分母及其倍數,其中位於區間[ki,(k+1)i)[k*i,(k+1)*i)裡的x的答案都會加上aia_i的值在這個區間裡的個數*k。

複雜度=O(m+m2+m3+...+mm)O(mlogm)O(m+\frac m2+\frac m3+...+\frac mm)\approx 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;
}