CF1872D Plus Minus Permutation

发布时间 2023-09-08 08:27:47作者: One_JuRuo

思路

又又又是一道 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);
	}
}