纯粹的数学-AT_abc147_f

这题感觉挺好的

首先,我们将 $\sum_{i \in S} a[i]-\sum_{i \notin S} a[i]$转化为$2*\sum_{i\in S} a[i]-\sum_{i=1}^na[i]$

我们容易发现,$\sum_{i=1}^na[i]$和$2$ 都是定值,问题转化为$\sum_{i\in S} a[i]$的不同和的数量

我们将$a[i]$拆开,得到$x+(i-1)*d$

我们考虑集合中有$t$个数的情况,他们和为$t*x+l*d$,$l$有连续区间$ \frac{t*(t-1)}{2} \le l \le \frac{(2*n-t-1)*t}{2}$,在$l$取前$t$小个数字时有最小值,取前$k$大个数字时有最大值

我们考虑出现重合的地方,我们注意到,当$t1*x \bmod d= t2*x \bmod d$时,取$t1$的值与取$t2$的值在一直线上,有且仅有这种情况会出现重合

我们将问题转换成直线上线段并,然后就可以解决它啦


```cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
int n,d,x,tot,ans=0;
map<int,int> m;
vector<pair<int,int>> vec[N];//pair自带按第一关键字排序 
signed main(){
    cin>>n>>x>>d;
    if(d==0){//特判 
        if(x==0) cout<<1<<endl;
        else cout<<n+1<<endl;
        return 0;
    }
    for(int i=0;i<=n;i++){
        int now=i*x%d;
        int lef=i*(i-1)/2,rig=(2*n-i-1)*i/2;
        if(d<0) swap(lef,rig);//特殊处理d<0的情况 
        if(m[now]==0){
            tot++;
            m[now]=tot;
        }
        vec[m[now]].push_back(make_pair(lef*d+i*x,rig*d+i*x));
    }
    d=abs(d); 
    for(int i=1;i<=tot;i++){
        sort(vec[i].begin(),vec[i].end());
        int lef=vec[i].front().first,rig=vec[i].front().second;
        ans+=(rig-lef)/d+1;
        for(auto j:vec[i]){
            if(j.second<=rig) continue; //当前区间被完全覆盖 
            if(j.first<=rig) ans+=(j.second-rig)/d; //当前区间与之前线段有重叠 
            else ans+=(j.second-j.first)/d+1; //当前线段与之前无重叠 
            rig=j.second; 
        }
    }
    cout<<ans;
}
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值