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
T≤104,n≤109,r≤104
∑
d
=
1
n
(
−
1
)
⌊
d
r
d
⌋
\sum\limits_{d=1}^n(-1)^{\lfloor\sqrt{drd}\rfloor}
d=1∑n(−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=1∑n(−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=1∑n1−2(⌊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=1∑n1−2⌊dx⌋+4⌊2dx⌋
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=0∑n⌊cai+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)=⌊ca⌋⋅2n(n+1)+⌊cb⌋⋅(n+1)+f(a%c,b%c,c,n)
if a < c && b < c then
要计算的就是上面阴影部分内的整点个数( 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=0∑ny=1∑m[cy≤ax+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=0∑ny=0∑m−1[x>(cy+c−b−1)/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
nm−y=0∑m−1⌊acy+c−b−1⌋
于是有
n
m
−
f
(
c
,
c
−
b
−
1
,
a
,
m
−
1
)
nm-f(c,c-b-1,a,m-1)
nm−f(c,c−b−1,a,m−1)
小时候看类欧直接被推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
n−2d=1∑n⌊dx⌋+4d=1∑n⌊2dx⌋
如果
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=1∑n⌊cax⋅d⌋
smjb.jpg
仿照一般类欧对
⌊
a
c
⋅
d
⌋
\left\lfloor\frac{a}{c}\cdot d\right\rfloor
⌊ca⋅d⌋ 的处理 为了方便设
k
=
a
x
c
k=\frac{ax}{c}
k=cax
如果
k
≥
1
k\ge1
k≥1 那么
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)=⌊cax⌋⋅2n(n+1)+f(a%c,c,n)
否则 令
m
=
⌊
a
x
c
⋅
n
⌋
m=\left\lfloor\frac{ax}{c}\cdot n\right\rfloor
m=⌊cax⋅n⌋
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=1∑ny=1∑m[y<cax⋅d+1]d=1∑ny=1∑m[d>axcy−c]nm−y=1∑m⌊ar(c−1)x⋅y⌋nm−f(c−1,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
k≥1,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<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
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;
}