1. 程式人生 > >Codechef:Short/SHORT

Codechef:Short/SHORT

傳送門

題解:
挺套路的。

a , b T a,b\ge T ,則 T

2 2 T N + N 2 T
2
N
2
T ( 2
+ 2 ) N T^2-2TN+N^2 \le \frac{T^2-N}{2} \Rightarrow T\le(2+\sqrt{2})N

然後列舉最小值 a a b = N + a N N k a k N a b = N+\frac{aN-N}{ka-kN-a} ,在 a a 較小的時候列舉 a N N aN-N 的約數,在 a a 較大時,有: 0 < k a N a a N a a N < k a 2 N ( a N ) 2 0 \lt ka-N-a \le a-N \Rightarrow \frac{a}{a-N} \lt k \le \frac{a^2-N}{(a-N)^2} 。實踐證明,跑得飛快。

#include <bits/stdc++.h>
using namespace std;
typedef __int128 IL;
typedef long long LL;

inline void W(IL ans) {
	static int buf[233];
	if(!ans) {puts("0"); return;}
	while(ans) buf[++buf[0]]=ans%10, ans/=10;
	while(buf[0]) putchar(buf[buf[0]--]+'0'); puts("");
}
const int L=400000;
int pr[L+50],mnpr[L+50],pt;
inline void init() {
	mnpr[1]=L+1;
	for(int i=2;i<=L;i++) {
		if(!mnpr[i]) mnpr[i]=pr[++pt]=i;
		for(int j=1;j<=pt;j++) {
			LL k=(LL)i*pr[j];
			if(k>L) break;
			mnpr[k]=pr[j];
			if(!(i%pr[j])) break;
		}
	}
}
const int LIM=6000;
LL n,K,ans;

inline void solve() {
	cin>>n>>K; ans=0;
	if(!n) {W((IL)(K-1)*(K-1)); return;} K--;
	for(LL a=n+1;a<=3.43*n && a<=K;a++) {
		if(a>n+LIM) {
			LL lim=(a*a-n)/((a-n)*(a-n)), p=a*n-n;
			for(LL k=a/(a-n)+1;k<=lim;k++) {
				LL b=n+p/(k*a-k*n-a);
				if(b<=K && !((a*b-n)%((a-n)*(b-n)))) ans+=(a!=b)+1;
			}
		} else {
			LL p1=a-1, p2=n;
			static LL div[L],dc; div[dc=1]=1;
			while(p1>1 || p2>1) {
				LL t=min(mnpr[p1],mnpr[p2]), c=0;
				while(mnpr[p1]==t) p1/=t, ++c;
				while(mnpr[p2]==t) p2/=t, ++c;
				for(int i=dc;i;i--) 
					for(LL j=1,v=1;j<=c;j++) div[++dc]=div[i]*(v*=t);
			}
			LL ori=(a-1)*n;
			for(int i=1;i<=dc;i++) {
				LL b=ori/div[i]+a;
				if(n+div[i]<=K && !(b%(a-n))) 
					if(n+div[i]>=a) ans+=(n+div[i]!=a)+1;
			} 
		}
	} W(ans);
}
int main() {
	init(); int T; cin>>T;
	while(T--) solve();
}