Banner 統計

題目描述:

LZN 搞完保送生考試,終於要回到信息組大家庭了,Chanxer 決定要好好地歡迎LZN,於是他在在操場上整齊地插了(M + 1) *(N + 1) 個標杆,形成了一個平面直角座標系,左下角的標杆的座標爲(0; 0),右上角的標杆的座標爲(M;N),Chanxer 現在想要選擇兩個標杆作爲端點連上橫幅“ 機房歡迎你”。

可是,由於Chanxer 很農,他不希望橫幅被其它的標杆攔住,因此他要求選擇的兩個標杆的連線不應該經過其它標杆,並且橫幅的長度還應該在[L;R]以內。

現在Chanxer 想要知道他有多少種選法,注意,由於橫幅的兩面是一模一樣的,所以選擇的兩個點沒有起點終點之分,鑑於答案可能很大,而又不允許上交Python、Java 等語言的源代碼,你只需要告訴他答案除以B 的餘數是多少就可以了。

題目分析:

我們設兩個兩個標杆橫座標的距離差爲x,縱座標的距離差爲y。
我們把x=0和y=0的情況刨出來單算:
只有L<=1的時候,這兩種情況纔有答案,答案爲n*(m+1)+m *(n+1)

剩下的就是:
這裏寫圖片描述

解釋一下這個式子的意思:枚舉x和y,答案加上滿足長度在範圍內且連線不經其他過格點(即gcd(x,y)==1)的方案。
對於一對固定的x和y,它的在橫向上最多可以取(m-x+1)個位置,在縱向上最多可以取(n-y+1)個位置,那麼可選的方案就共有(m-x+1)*(n-y+1)種,但是這條線段可以向上傾斜也可以向下傾斜,所以答案要乘2。

我們只需要枚舉x和y,當然如果暴力枚舉的話肯定GG。
觀察這個式子,可以觀察出,x只需要枚舉到min(m,R),而當x固定的時候,y只需要在區間[sqrt(L* L-x *x),sqrt(R *R-x *x) ]內枚舉即可,即可以省掉長度範圍的判斷。
按照上述條件把原式進行變形:
這裏寫圖片描述

我們設 l 爲枚舉y的下限,r爲枚舉y的上限。
於是問題轉化成了,如何求:
這裏寫圖片描述

即如何快速求出:
這裏寫圖片描述
(lim和x是給定的)

這個時候可以利用莫比烏斯函數進行容斥,即該式可以轉化爲:
這裏寫圖片描述
上面這個轉化不懂的可以選擇看看我的Zap的題解:
http://blog.csdn.net/todobe/article/details/60579910
也可以根據莫比烏斯函數求和的性質,只有gcd爲1的時候莫比烏斯函數的和爲1,其他時候都爲0,乘上方案數相加之後恰好爲所求答案。

這樣我們只要用sqrt(x)的時間枚舉x的約數,然後∑(d|y)(n-y+1)是可以O(1)算出的。
不會O(1)算的小夥伴看這裏:
我們設一個臨時變量t=lim/d(因爲是要求lim範圍內合法的y嘛)
這個t代表共有t個合法的y,分別爲:d,2d,3d……td;
我們要求的就是把這些y分別帶入(n-y+1)裏面然後求和。
這樣我們把常量(n+1)提出來,就是(n+1)* t +((1+t)* t /2)*d
這樣就算出來了(你們看完之後是不是覺得寫題解的人非常智障啊=。=)

時間複雜度O(nsqrt(n))
其實後面的部分也可以不用莫比烏斯函數來做,直接容斥也可以。
(但是本寶寶是蒟蒻T^T,只會這種)

注意:

在計算第二維的下限的時候要和1取一個max,因爲0的情況你已經單算了,如果枚舉的x(即我代碼裏的i)已經大於L的時候,它的下限直接設爲1即可

代碼如下:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define N 120000
using namespace std;
typedef long long LL;
inline LL sqr(LL x) { return x*x; }
LL n,m,L,R,mod,ans;
inline LL sum(LL x) { return (x*(x+1)>>1)%mod; }
bool mark[N];
LL pri[N],u[N];
int top;
void init()
{
    u[1]=1;
    for(LL i=2;i<N;i++)
    {
        if(!mark[i])
        {
            pri[++top]=i;
            u[i]=-1;
        }
        for(int j=1;j<=top && pri[j]*i<N;j++)
        {
            mark[i*pri[j]]=true;
            if(i%pri[j]==0)
            {
                u[i*pri[j]]=0;
                break;
            }
            u[i*pri[j]]=-u[i];
        }
    }
}
LL calc(LL lim,LL x)
{
    LL ans=0;
    LL t,i;
    for(i=1;i*i<x;i++)
    {
        if(x%i==0)
        {
            t=lim/i;
            ans+=(u[i]*((n+1)*t%mod-sum(t)*i%mod)+mod)%mod,ans%=mod;
            t=lim/(x/i);
            ans+=(u[x/i]*((n+1)*t%mod-sum(t)*(x/i)%mod)+mod)%mod,ans%=mod;
        }
    }
    if(i*i==x)
    {
        t=lim/i;
        ans+=(u[i]*((n+1)*t%mod-sum(t)*i%mod)+mod)%mod,ans%=mod;
    }
    return ans;
}
int main()
{
    init();
    cin>>n>>m>>L>>R>>mod;
    for(LL i=1;i<=min(m,R);i++)
    {
        LL l=i>L?1:max(1ll,LL(ceil(sqrt(sqr(L)-sqr(i)))));
        LL r=min(n,LL(sqrt(sqr(R)-sqr(i))));
        if(l<=r) ans+=(calc(r,i)-calc(l-1,i)+mod)%mod*(m-i+1)%mod*2%mod,ans%=mod;
    }
    if(L<=1) ans+=m*(n+1)%mod+n*(m+1)%mod,ans%=mod;
    cout<<ans<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章