题目链接
求:
∑ d = 1 n ( − 1 ) ⌊ d ∗ r ∗ d ⌋ \sum_{d=1}^{n} (-1)^{\big\lfloor \sqrt{d*r*d} \big \rfloor} d=1∑n(−1)⌊d∗r∗d⌋
就是:
∑ d = 1 n ( − 1 ) ⌊ d r ⌋ \sum_{d=1}^{n} (-1)^{\big\lfloor d\sqrt{r} \big \rfloor} d=1∑n(−1)⌊dr⌋
如果 r r r是完全平方数直接算,反之:
显然我们只需要知道有多少个 ⌊ d r ⌋ \big\lfloor d\sqrt{r} \big \rfloor ⌊dr⌋为奇数或偶数,那么想到这样化个式子:
∑ d = 1 n ( 1 − 2 ∗ ( ⌊ d r ⌋ m o d 2 ) \sum_{d=1}^n (1-2*\big (\lfloor d\sqrt r \rfloor \ mod\ 2 \big ) d=1∑n(1−2∗(⌊dr⌋ mod 2)
然后用除法拆掉 mod,化简,记 x = r x=\sqrt r x=r
n − 2 ∗ ∑ d = 1 n ( ⌊ d x ⌋ − ⌊ d x 2 ⌋ ∗ 2 ) n-2*\sum_{d=1}^n \big (\lfloor dx \rfloor-\lfloor \frac{dx}{2} \rfloor*2 \big) n−2∗d=1∑n(⌊dx⌋−⌊2dx⌋∗2)
于是只需要会求解:
∑ i = 1 n ⌊ A C ∗ i ⌋ \sum_{i=1}^{n} \bigg \lfloor \frac{A}{C}*i \bigg \rfloor i=1∑n⌊CA∗i⌋
但是由于这里 A A A是一个实数,直接做会有精度误差,为了类欧的需要,所以可以用带上 x x x的项来表示:
∑ i = 1 n ⌊ A x + B C ∗ i ⌋ \sum_{i=1}^{n} \bigg \lfloor \frac{Ax+B}{C}*i \bigg \rfloor i=1∑n⌊CAx+B∗i⌋
这样就是个比较裸的类欧了,用矩形中的整点个数减去上三角的整点个数,由于 A A A的后面有个 x x x,我们不能够直接把 A A A 模掉 C C C,所以可以直接把多的 A A A 减在 B B B上,这样问题的规模就可以缩小了,因为 n n n 会不断变小
设 m = ⌊ A x + B C ∗ n ⌋ m=\lfloor \dfrac{Ax+B}{C}*n \rfloor m=⌊CAx+B∗n⌋,那么把该直线关于 y = x y=x y=x对称( 斜 率 之 积 为 1 斜率之积为1 斜率之积为1),分母有理化后,可得以下递推式:
F ( n , A , B , C ) = n ∗ m − F ( m , A ∗ C , − C ∗ B , A ∗ A ∗ r − B ∗ B ) F(n,A,B,C)=n*m-F(m,A*C,-C*B,A*A*r-B*B) F(n,A,B,C)=n∗m−F(m,A∗C,−C∗B,A∗A∗r−B∗B)
其中 F ( n , A , B , C ) F(n,A,B,C) F(n,A,B,C)表示参数为这些值时的答案
#include
using namespace std;
typedef long double ldb;
typedef long long ll;
template<class T>inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
ldb R;
ll n,r;
ll gcd(ll a,ll b){return b? gcd(b,a%b):a;}
ll likegcd(ll n,ll A,ll B,ll C){
if(!n) return 0;
int d=gcd(A,gcd(B,C));A/=d,B/=d,C/=d;//除掉 gcd 可以防止爆 long long
ldb K=((ldb)A*R+(ldb)B)/(ldb)C;ll k=(ll)(K);
B-=k*C;//是把多的 A 减在 B 上面 !
K=K-1.00*k;ll m=(ll)(K*n);
ll ret=n*(n+1)/2*k;
return ret+n*m-likegcd(m,A*C,-C*B,A*A*r-B*B);
}
int main()
{
int T;init(T);
while(T--){
init(n);init(r);R=sqrt((ldb)r);ll g=(ll)(R);
if(g*g==r) {if(r&1) printf("%d\n",(n&1)? (-1):0);else printf("%d\n",n);}
else {
ll ans=1ll*n-((likegcd(n,1,0,1)-(likegcd(n,1,0,2)<<1))<<1);
printf("%lld\n",ans);
}
}
}