题解:AT_abc147_f [ABC147F] Sum Difference

题意

在一个等差数列中取出若干个元素,求取出的元素与未取出的元素的差值有多少种可能。

思路

首先,我们有一个式子:

\[w(i)=\sum_{i \in S}A_i-\sum_{i \notin S}A_i \]

不难看出,该式可以变为:

\[w(i)=2\times \sum_{i \in S}A_i-\sum_{i=1}^{n}A_i \]

其实,\(\sum_{i=1}^{n}+A_i\)\(2\) 是一个定值,所以我们只需求出 \(\sum_{i \in S}A_i\) 的不同和即可。

不难看出 \(A_i=X+(i-1)\times num\),其中 \(X\) 为首项,\(num\) 为公差。

所以,假如我们选取了 \(t\) 个数,那它们的总和必定为 \(tX+num \times s\)

\(s\) 如何求?

不难看出,最小的肯定是选前 \(t\) 个,最大的则是选后 \(t\) 个,所以 \(s\) 的范围为 \([\frac{t\times(t-1)}{2} ,\frac{(2n-1-t)\times t}{2}]\)

但是,我们还需要考虑覆盖的情况,也就是:

\[t_i\times x+k_i\times num=t_j\times x+k_j\times num \]

移项得:

\[(t_i-t_j)\times x=(k_j-k_i)\times num \]

可推出:

\[num \mid (t_i-t_j)\times x \]

可得 \(t_i \times x\)\(t_j \times x\) 对模 \(num\) 同余。

所以,我们可以直接把 \(t_i \times x\)\(t_j \times x\) 余数相等的放到一起,求一下区间覆盖即可。

Code

#include<bits/stdc++.h>
#define int long long 
using namespace std;
int n,x,num,ans;
struct node{
    int l,r;
    bool operator<(const node& x)const{return l<x.l;}
};
vector<node> v[2000005];
map<int,int> M;
int cnt;
signed main(){
    scanf("%lld%lld%lld",&n,&x,&num);
    if(!num){
        if(!x) puts("1");
        else printf("%lld\n",n+1);
        return 0;
    }
    for(int t=0;t<=n;t++){
        if(!M[t*x%num]) M[t*x%num]=++cnt;
        v[M[t*x%num]].push_back({t*(t-1)/2+(t*x/num),(2*n-1-t)*t/2+(t*x/num)});
    }
    for(int i=1;i<=cnt;i++){
        sort(v[i].begin(),v[i].end());
        int L=v[i][0].l,R=v[i][0].r;
        for(int j=1;j<v[i].size();j++){
            if(v[i][j].l<=R) R=max(v[i][j].r,R);
            else ans+=(R-L+1),L=v[i][j].l,R=v[i][j].r;
        }
        ans+=(R-L+1);
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2025-11-09 18:33  fengenrong  阅读(3)  评论(0)    收藏  举报