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
#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;
}