BZOJ3817:Sum(類歐幾里得)
阿新 • • 發佈:2019-02-01
題意:
給定正整數
題解:
有點像類歐幾里得。
只需要知道:
又因為
那麼問題轉化為求
顯然這是一條從原點出發的直線,要求的是它的下半部分的整數點。
有一個結論是如果這條直線的斜率大於1,那麼先減掉1的斜率並加上這個斜率帶來的一個直角三角形的貢獻,這個新得到的直線覆蓋的整點即為原來直線還沒有加上的點。
類似於歐幾里得,現在我們得到了一個斜率小於1的直線,那麼考慮翻轉這個座標系來列舉y軸,發現又變成了一個子問題,這樣迭代只會進行 n)
具體的實現由於精度問題,我寫的
先計算出在
Fastio部分可以忽略掉
#include<bits/stdc++.h>
typedef long long ll;
typedef long double db;
using namespace std;
const int R_LEN=(1<<18)|1;
struct Fast_io{
char ibuf[R_LEN],obuf[R_LEN],*s,*t,*wt;
int buf[50];
Fast_io(){s=ibuf,t=ibuf; wt=obuf;}
~Fast_io(){fwrite(obuf,1,wt-obuf,stdout);}
inline void print(char c){
(wt==(obuf+R_LEN)) && (fwrite(obuf,1 ,R_LEN,stdout),wt=obuf);
*wt++=c;
}
template<typename T>
inline void W(T x){
if(x<0){print('-');x=-x;}
if(!x){print('0');return;}
while(x){buf[++buf[0]]=x%10;x/=10;}
while(buf[0])print(buf[buf[0]--]+'0');
}
inline char getc(){
(s==t) && (t=(s=ibuf)+fread(ibuf,1,R_LEN,stdin));
return (s==t)?-1:*s++;
}
inline int rd(){
char ch=getc(); int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1; ch=getc();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getc();}
return i*f;
}
}io;
int T,n,r;db R,mxlen;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll solve(ll a,ll b,ll c,ll len){
if(!len) return 0;
ll t=gcd(a,gcd(b,c)); a/=t; b/=t; c/=t;
t=(a*R+b)/c; ll sum=(len*(len+1)>>1)*t;
b-=c*t; t=(a*R+b)*len/c;
return sum+t*len-solve(a*c,-b*c,a*a*r-b*b,t);
}
int main(){
for(T=io.rd();T;T--){
n=io.rd(),r=io.rd();
R=sqrt(r); int t=(int)(R+0.5);
if(t*t==r){io.W((t&1)?((n&1)?-1:0):n);io.print('\n');continue;}
int odd_cnt=solve(1,0,1,n);
odd_cnt-=2*solve(1,0,2,n);
io.W(n-2*odd_cnt),io.print('\n');
}
}