标签:tmp kx int 题解 Sum include second Difference sum
模拟赛做到的,结果两个小时都没想出来。
题目要求一个人在等差数列中选一些数,另一个人选剩下的,求他们选的数差的不同个数。
那么设一个人选的和为 \(w\), 总和是 \(sum\), 两个人的差就是 \(2w-sum\), 因为 \(sum\) 不变,所以只要求出 \(w\) 的不同个数就可以了。
设一个人选的数的下标集合是 \(T\), 那么 \(w = x|T| + \sum_{i \in T} (i-1)d\),将 \(d\) 提出,再设 \(k = |T|, v = \sum_{i \in T} (i-1)\), 式子变成了 \(w = kx + vd\)。再想想 \(v\) 的取值范围,因为 \(i-1\) 是在 \([0, n-1]\) 之间连续的,所以我们非常好确定 \(v\) 的范围,就是 \([\sum_{i=0}^{k-1}i,\ i\cdot n - \sum_{i=1}^ki]\)。
考场上想到也许可以容斥,先把这所有的区间内的个数都加起来,然后找到类似 \(k_1 d = k_2 x\) 的式子去把重复的给减掉,但是这样细节繁多,而且时间上也过不去。
然后就是本题的关键想法:\(kx + vd\) 在模 \(d\) 意义下肯定是相同的。这意味着可以按 \(kx\) 分类,不同类中的肯定是不同的,所以只要处理 \(kx\) 模 \(d\) 相同的行的数就可以了。
我们可以把所有 \(kx\) 模 \(d\) 相同的数转换成数轴的一段。因为同一行的数都间隔 \(d\), 那么同一行就可以直接用 \(v\) 的值来表示,至于处理不同行,只需要将 \(v\) 的左右端点都加上 \(\frac{kx}{d}\) 就可以了。
然后就变成了简单的线段求并。
代码。
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#define int long long
int n, x, d, ans;
typedef std::vector<std::pair<int, int> > twt;
std::map<int, twt> map;
signed main() {
scanf("%lld%lld%lld", &n, &x, &d);
if(x == 0 && d == 0) return puts("1"), 0;
if(x != 0 && d == 0) return printf("%lld\n", n+1), 0;
if(d < 0) x = -x, d = -d;
for(int i = 0; i <= n; i++) {
int t = i*x, L = (i-1)*i/2+t/d, R = i*n-(i+1)*i/2+t/d;
t %= d;
if(t < 0) t += d;
map[t].push_back(std::make_pair(L, R));
}
for(std::map<int, twt>::iterator it = map.begin(); it != map.end(); it++) {
twt tmp = (*it).second;
if(!tmp.size()) continue;
std::sort(tmp.begin(), tmp.end());
int l = tmp[0].first, r = tmp[0].second;
for(int j = 1; j < (signed)tmp.size(); j++)
if(tmp[j].first > r) ans += r-l+1, l = tmp[j].first, r = tmp[j].second;
else r = std::max(r, tmp[j].second);
ans += r-l+1;
}
printf("%lld", ans);
}
标签:tmp,kx,int,题解,Sum,include,second,Difference,sum 来源: https://www.cnblogs.com/Acfboy/p/14880055.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。