[BZOJ3817] [清华集训2014] Sum [类欧]

Link
BZOJ - https://lydsy.com/JudgeOnline/problem.php?id=3817


d r d(警觉)
世 界 名 曲
DANCE ROBOT DANCE (幻视


T ≤ 1 0 4 , n ≤ 1 0 9 , r ≤ 1 0 4 T\le10^4,n\le10^9,r\le10^4 T104,n109,r104
∑ d = 1 n ( − 1 ) ⌊ d r d ⌋ \sum\limits_{d=1}^n(-1)^{\lfloor\sqrt{drd}\rfloor} d=1n(1)drd


Let x = r x=\sqrt{r} x=r
Then a n s = ∑ d = 1 n ( − 1 ) ⌊ d x ⌋ ans=\sum\limits_{d=1}^n(-1)^{\lfloor dx\rfloor} ans=d=1n(1)dx
Obviously a n s = ∑ d = 1 n 1 − 2 ( ⌊ d x ⌋ & 1 ) ans=\sum\limits_{d=1}^n1-2(\lfloor dx\rfloor\&1) ans=d=1n12(dx&1)
a n s = ∑ d = 1 n 1 − 2 ⌊ d x ⌋ + 4 ⌊ d x 2 ⌋ ans=\sum\limits_{d=1}^n1-2\lfloor dx\rfloor+4\left\lfloor\frac{dx}{2}\right\rfloor ans=d=1n12dx+42dx


Q. f ( a , b , c , n ) = ∑ i = 0 n ⌊ a i + b c ⌋ f(a,b,c,n)=\sum\limits_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor f(a,b,c,n)=i=0ncai+b
If a>=c || b>=c then f ( a , b , c , n ) = ⌊ a c ⌋ ⋅ n ( n + 1 ) 2 + ⌊ b c ⌋ ⋅ ( n + 1 ) + f ( a % c , b % c , c , n ) f(a,b,c,n)=\left\lfloor\frac{a}{c}\right\rfloor\cdot\frac{n(n+1)}{2}+\left\lfloor\frac{b}{c}\right\rfloor\cdot (n+1)+f(a\%c,b\%c,c,n) f(a,b,c,n)=ca2n(n+1)+cb(n+1)+f(a%c,b%c,c,n)
if a < c && b < c then
[BZOJ3817] [清华集训2014] Sum [类欧]_第1张图片
要计算的就是上面阴影部分内的整点个数( y > 0
显然现在要做的是缩小 c 才能继续计算下去
先考虑枚举两维坐标?
∑ x = 0 n ∑ y = 1 m [ c y ≤ a x + b ] \sum\limits_{x=0}^n\sum\limits_{y=1}^{m}[cy\le ax+b] x=0ny=1m[cyax+b]
发现这个时候可以把 a 转为分母,然后 c 变成 a 就缩小了规模
∑ x = 0 n ∑ y = 0 m − 1 [ x > ( c y + c − b − 1 ) / a ] \sum\limits_{x=0}^n\sum\limits_{y=0}^{m-1}[x>(cy+c-b-1)/a] x=0ny=0m1[x>(cy+cb1)/a]
n m − ∑ y = 0 m − 1 ⌊ c y + c − b − 1 a ⌋ nm-\sum\limits_{y=0}^{m-1}\left\lfloor\frac{cy+c-b-1}{a}\right\rfloor nmy=0m1acy+cb1
于是有 n m − f ( c , c − b − 1 , a , m − 1 ) nm-f(c,c-b-1,a,m-1) nmf(c,cb1,a,m1)


小时候看类欧直接被推f 推g 推h三连吓到了
好像实际上挺simple的(?


总之这题最后就是求 n − 2 ∑ d = 1 n ⌊ d x ⌋ + 4 ∑ d = 1 n ⌊ d x 2 ⌋ n-2\sum\limits_{d=1}^n\lfloor dx\rfloor+4\sum\limits_{d=1}^n\left\lfloor\frac{dx}{2}\right\rfloor n2d=1ndx+4d=1n2dx
如果 x 2 = r x^2=r x2=r 可以直接求 所以下面默认 x x x 是无理数了。

首先要注意这道题 x x x 并不一定是整数
f ( a , c , n ) = ∑ d = 1 n ⌊ a x c ⋅ d ⌋ f(a,c,n)=\sum\limits_{d=1}^n\left\lfloor\frac{ax}{c}\cdot d\right\rfloor f(a,c,n)=d=1ncaxd
smjb.jpg
仿照一般类欧对 ⌊ a c ⋅ d ⌋ \left\lfloor\frac{a}{c}\cdot d\right\rfloor cad 的处理 为了方便设 k = a x c k=\frac{ax}{c} k=cax
如果 k ≥ 1 k\ge1 k1 那么 f ( a , c , n ) = ⌊ a x c ⌋ ⋅ n ( n + 1 ) 2 + f ( a % c , c , n ) f(a,c,n)=\left\lfloor\frac{ax}{c}\right\rfloor\cdot\frac{n(n+1)}{2}+f(a\%c,c,n) f(a,c,n)=cax2n(n+1)+f(a%c,c,n)
否则 令 m = ⌊ a x c ⋅ n ⌋ m=\left\lfloor\frac{ax}{c}\cdot n\right\rfloor m=caxn
f ( a , c , n ) = ∑ d = 1 n ∑ y = 1 m [ y < a x c ⋅ d + 1 ] = ∑ d = 1 n ∑ y = 1 m [ d > c y − c a x ] = n m − ∑ y = 1 m ⌊ ( c − 1 ) x a r ⋅ y ⌋ = n m − f ( c − 1 , a r , m ) \begin{array}{rcl} f(a,c,n)&=&\sum\limits_{d=1}^n\sum\limits_{y=1}^m\left[y<\frac{ax}{c}\cdot d+1\right]\\ &=&\sum\limits_{d=1}^n\sum\limits_{y=1}^m\left[d>\frac{cy-c}{ax}\right]\\ &=&nm-\sum\limits_{y=1}^m\left\lfloor\frac{(c-1)x}{ar}\cdot y\right\rfloor\\ &=&nm-f(c-1,ar,m) \end{array} f(a,c,n)====d=1ny=1m[y<caxd+1]d=1ny=1m[d>axcyc]nmy=1mar(c1)xynmf(c1,ar,m)
递归边界 n = 0 n=0 n=0 时间复杂度 O ( T L E ) O(TLE) O(TLE)
为什么?
类欧的复杂度/正确性一定需要 a , b , c , n a,b,c,n a,b,c,n 来保证。原因是我写了之后发现会炸idk tbh

所以重推
k ≥ 1 , f ( a , b , c , n ) = ⋯ k\ge1,f(a,b,c,n)=\cdots k1,f(a,b,c,n)=
o t h e r w i s e … otherwise\dots otherwise
最后可以得到一个 O ( log ⁡ ) O(\log) O(log) 的算法
复杂度分析我不会感觉化一下也许就能变成正常类欧的复杂度分析(?


Tips.
为了不会炸飞,每次类欧的时候可以把 a, b, c 同除 gcd
正确性显然,,,


#include
#include
#include
#include
#include
#include
#include
using namespace std;
int T;
long long n, r, ans, k;
double x, t;
long long gcd(const long long& a, const long long& b)
{
	return !b?a:gcd(b,a%b);
}
long long f(long long a, long long b, long long c, long long n)
{
	if (n <= 0) return 0;
	if (!a) return 0;
	k = gcd(a, gcd(b, c));  a /= k; b /= k; c /= k;
	t = (x * a + b) / c; k = t;
	if (k) return k * (n * (n + 1) / 2) + f(a, b - c * k, c, n);
	t *= n;
	return n * floor(t) - f(a * c,  -b * c, a * a * r - b * b, t);
}
int main()
{
	scanf("%d", &T);
	while (T--)
	{
		scanf("%lld%lld", &n, &r);
		x = sqrt(r);
		k = floor(x);
		ans = n;
		if (k * k == r)
		{
			if (k & 1) puts((n&1)?"-1":"0");
			else printf("%lld\n", n);
			continue;
		}
		ans -= (f(1, 0, 1, n) << 1);
		ans += (f(1, 0, 2, n) << 2);
		printf("%lld\n", ans);
	}
	return 0;
}

你可能感兴趣的:(BZOJ,类欧)