BZOJ 3817 Sum
Description
给定正整数N,R。求
Input
第一行一个数 T,表示有 T 组测试数据。
接下来 T 行,每行两个正整数 n,r。
Output
输出 T 行,每行一个整数表示答案。
Sample Input
3
3 5
3 6
3 7
3 5
3 6
3 7
Sample Output
3
1
-1
1
-1
HINT
对于 100% 的数据,满足 n≤10^9,r≤10^4,T≤10^4。
关于类欧几里得的介绍:ZYYS
设$x=\sqrt r$,则
$$
\begin{align}
-1^{dx } & =1-2( dx \% 2) \\
&=1-2(dx - \frac{dx}{2} * 2) \\
&= 1+4\frac{dx}{2} + 2 dx
\end{align}
$$
那么
$$原式 =n + 4 \sum_{d=1}^{n} \frac{dx}{2}-2\sum_{d=1}^{n}dx$$
$$
\begin{align}
-1^{dx } & =1-2( dx \% 2) \\
&=1-2(dx - \frac{dx}{2} * 2) \\
&= 1+4\frac{dx}{2} + 2 dx
\end{align}
$$
那么
$$原式 =n + 4 \sum_{d=1}^{n} \frac{dx}{2}-2\sum_{d=1}^{n}dx$$
但系数是一个实数,写作$ans=\sum_{i=1}^{n}\lfloor k*i \rfloor$
$k=\frac{a*x+b}{c}$ 这里x等于根号r
类欧的套路,将其转化为函数含义,也就是:
函数$y=k*x$与x轴,与$x=1$和$x=n$围成的梯形有多少整点
为了方便,这里不考虑函数线上的整点,而在开始特判(显然有整点代表x为整数)
如果$k<1$
那么有
$ans=\sum_{i=1}^{n}\sum_{j=1}^{\lfloor k*n \rfloor}[k*i>j]$
按照类欧的套路,移项
$ans=\sum_{i=1}^{n}\sum_{j=1}^{\lfloor k*n \rfloor}[i>\lfloor \frac{j}{k} \rfloor]$
交换枚举顺序
$ans=\sum_{j=1}^{\lfloor k*n \rfloor}n-\lfloor \frac{j}{k} \rfloor$
$ans=\lfloor k*n \rfloor*n-\sum_{j=1}^{\lfloor k*n \rfloor}\lfloor \frac{j}{k} \rfloor$
把$\frac{1}{k}$的分母有理化,发现后面这部分可以递归
我们发现在$k<1$递归$\frac{1}{k}$时,下一个$k$会大于1,这样下一个$n$会变大
我们可以用这个方法;
$ans=\sum_{i=1}^{n}\lfloor k*i \rfloor$
$ans=\sum_{i=1}^{n}\lfloor k*i-\lfloor k \rfloor*i+\lfloor k \rfloor*i \rfloor$
$ans=\sum_{i=1}^{n}\lfloor k*i-\lfloor k \rfloor*i \rfloor+\lfloor k \rfloor*i$
$ans=\lfloor k \rfloor*\frac{n*(n+1)}{2}+\sum_{i=1}^{n}\lfloor k*i-\lfloor k \rfloor*i \rfloor$
$\lfloor k*i-\lfloor k \rfloor*i \rfloor=\lfloor \frac{a*x+b-c*\lfloor \frac{a*x+b}{c} \rfloor}{c} *i\rfloor$
把当前的$k$替换
$k=\frac{a*x+b-c*\lfloor \frac{a*x+b}{c} \rfloor}{c}$
这样$k$就小于1了
然后按$k<1$的情况递归
由于每次$n$都会乘以一个小于1的数,所以复杂度大概是$O(logn)$
不过为了防止暴longlong要提出gcd,用辗转相除
最后复杂度是$O(Tlog^{2}n)$
那么有
$ans=\sum_{i=1}^{n}\sum_{j=1}^{\lfloor k*n \rfloor}[k*i>j]$
按照类欧的套路,移项
$ans=\sum_{i=1}^{n}\sum_{j=1}^{\lfloor k*n \rfloor}[i>\lfloor \frac{j}{k} \rfloor]$
交换枚举顺序
$ans=\sum_{j=1}^{\lfloor k*n \rfloor}n-\lfloor \frac{j}{k} \rfloor$
$ans=\lfloor k*n \rfloor*n-\sum_{j=1}^{\lfloor k*n \rfloor}\lfloor \frac{j}{k} \rfloor$
把$\frac{1}{k}$的分母有理化,发现后面这部分可以递归
我们发现在$k<1$递归$\frac{1}{k}$时,下一个$k$会大于1,这样下一个$n$会变大
我们可以用这个方法;
$ans=\sum_{i=1}^{n}\lfloor k*i \rfloor$
$ans=\sum_{i=1}^{n}\lfloor k*i-\lfloor k \rfloor*i+\lfloor k \rfloor*i \rfloor$
$ans=\sum_{i=1}^{n}\lfloor k*i-\lfloor k \rfloor*i \rfloor+\lfloor k \rfloor*i$
$ans=\lfloor k \rfloor*\frac{n*(n+1)}{2}+\sum_{i=1}^{n}\lfloor k*i-\lfloor k \rfloor*i \rfloor$
$\lfloor k*i-\lfloor k \rfloor*i \rfloor=\lfloor \frac{a*x+b-c*\lfloor \frac{a*x+b}{c} \rfloor}{c} *i\rfloor$
把当前的$k$替换
$k=\frac{a*x+b-c*\lfloor \frac{a*x+b}{c} \rfloor}{c}$
这样$k$就小于1了
然后按$k<1$的情况递归
由于每次$n$都会乘以一个小于1的数,所以复杂度大概是$O(logn)$
不过为了防止暴longlong要提出gcd,用辗转相除
最后复杂度是$O(Tlog^{2}n)$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 typedef long long lol; 8 double t; 9 lol r; 10 lol gcd(lol a,lol b) 11 { 12 if (!b) return a; 13 return gcd(b,a%b); 14 } 15 lol cal(lol a,lol b,lol c,lol n) 16 { 17 if (n==0) return 0; 18 lol g=gcd(a,gcd(b,c)); 19 a/=g;b/=g;c/=g; 20 lol k=(t*a+b)/c; 21 lol ans=n*(n+1)/2*k; 22 b-=k*c; 23 k=(t*a+b)/c*n; 24 ans+=k*n-cal(a*c,-b*c,a*a*r-b*b,k); 25 return ans; 26 } 27 int main() 28 {int T; 29 lol n,ans; 30 cin>>T; 31 while (T--) 32 { 33 scanf("%lld%lld",&n,&r); 34 t=sqrt((double)r); 35 if ((lol)t==t) 36 { 37 if ((lol)t%2==0) 38 { 39 printf("%lld\n",n); 40 } 41 else 42 { 43 if (n%2==0) 44 printf("0\n"); 45 else printf("-1\n"); 46 } 47 } 48 else 49 { 50 ans=n+(cal(1,0,2,n)<<2)-(cal(1,0,1,n)<<1); 51 printf("%lld\n",ans); 52 } 53 } 54 }