Description
Analysis
一個很自然的想法是,由於k很大,我們二分一個分數,統計網格有多少個比它大
先不考慮如何二分分數,假裝我們已經得到了分數ba,如何統計比它大的個數呢?直線上整點個數,媽媽我會類歐
類歐
我們要求的是這個f(a,b,c,n)=∑i=0n⌊cai+b⌋
Case 1
若a≥c或b≥c顯然可以分離出常數項來,這是trivial的,此時
f(a,b,c,n)=f(a%c,b%c,c,n)+2cn(n+1)a+c(n+1)b
不在話下
Case 2
a<c且b<c,把上面那條搬下來,搞一波事情
f(a,b,c,n)=∑i=0n⌊cai+b⌋
魔幻的一步:令m=⌊can+b⌋
則f(a,b,c,n)=∑i=0n∑j=1m[cai+b≥j]
=∑i=0n∑j=0m−1[ai≥jc+c−b]
=∑i=0n∑j=0m−1[ai>jc+c−b−1]
=∑i=0n∑j=0m−1[i>ajc+c−b−1]
左邊只與i有關,爽了
=∑j=0m−1n−⌊ajc+c−b−1⌋
=nm−f(c,c−b−1,a,m−1)
我們發現第一、三個參數在模了之後調換了位置,這類似於歐幾里得算法,並且由歐幾里得算法知,這麼迭代下去複雜度也是一個log
代碼
ll f(ll a,ll b,ll c,ll n)//sigma (ai+b)/c
{
if(a==0) return n*(b/c);
if(a>=c || b>=c) return f(a%c,b%c,c,n)+n*(n+1)/2*(a/c)+(n+1)*(b/c);
ll m=(a*n+b)/c;
return n*m-f(c,c-b-1,a,m-1);
}
二分
然而二分分數是個棘手的問題(聽說可以二分實數強轉但具體不清楚)
今年WC上講了一個叫傻逼樹(Stern Brocot Tree)的東西來生成所有既約分數的姿勢,詳見scape鴿鴿的課件
在這棵樹上遍歷就相當於二分過程啦><
然而並不能一步步走qwq,注意到樹的深度是O(n)的,但是這棵樹一個性質是,從根走到任意一個分數,拐彎的次數不超過Log次
那麼在走的時候二分一下拐點就可以了
單次查詢就是3個log的