CF1872D Plus Minus Permutation
思路
又又又是一道 CF 诈骗题。
对于 \(x\) 选出来的数,我们尽量放大的,对于 \(y\) 选出来的数,我们尽量放小的,但是呢,存在同时被 \(x\) 和 \(y\) 选出来的数,就随便放。
但是可以发现按照题目给的数据范围,这么找选择的数,然后放最大或者是放最小,肯定是超时。
所以我们可以直接算出有多少个 \(x\) 选出来的数和有多少个 \(y\) 选出来的数以及有多少个同时被 \(x\) 和 \(y\) 选出来的数就可以了。
很显然的,\(x\) 能选 \(\lfloor \frac n x \rfloor\) 个数,\(y\) 能选 \(\lfloor \frac n y \rfloor\) 个数,同时被 \(x\) 和 \(y\) 选的数有 \(\lfloor \frac n {\gcd(x,y)}\rfloor\) 个。
所以我们把只被 \(x\) 选的 \(\lfloor \frac n x \rfloor-\lfloor \frac n {\gcd(x,y)}\rfloor\) 个数都放成最大的,用等差数列求和就是 \(\frac {[n+n-(\lfloor \frac n x \rfloor-\lfloor \frac n {\gcd(x,y)}\rfloor)+1]*(\lfloor \frac n x \rfloor-\lfloor \frac n {\gcd(x,y)}\rfloor)} 2\)。
再把只被 \(y\) 选的 \(\lfloor \frac n y \rfloor-\lfloor \frac n {\gcd(x,y)}\rfloor\) 个数都放成最小的,用等差数列求和就是 \(\frac {(1+\lfloor \frac n y \rfloor-\lfloor \frac n {\gcd(x,y)}\rfloor)*(\lfloor \frac n y \rfloor-\lfloor \frac n {\gcd(x,y)}\rfloor)} 2\)。
式子看着复杂,实际上很简单,自己想一想就能明白。
AC code
#include<bits/stdc++.h>
using namespace std;
long long T,n,a,b,lc,dn,xn;
int main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&a,&b),lc=a*b/__gcd(a,b),dn=n/a-n/lc,xn=n/b-n/lc;
printf("%lld\n",(n+n-dn+1)*dn/2-(1+xn)*xn/2);
}
}