2017.07.15【NOIP提高組】模擬賽B組 不等式(solve) 題解

原題:

http://172.16.0.132/senior/#contest/show/2061/2

題目描述:

小z熱衷于數學。
今天數學課的內容是解不等式:L<=Sx<=R。小z心想這也太簡單了,不禁陷入了深深的思考:假如已知L、R、S、M,滿足L<=(Sx)mod M<=R的最小正整數x該怎么求呢?

輸入:

第一行包含一個整數T,表示數據組數,接下來是T行,每行為四個正整數M、S、L、R。

輸出:

對于每組數據,輸出滿足要求的x值,若不存在,輸出-1。

樣例輸入:

1
5 4 2 3

樣例輸出:

2

數據范圍限制:

30%的數據中保證有解并且答案小于等于10^6;
另外20%的數據中保證L=R;
100%的數據中T<=100,M、S、L、R<=10^9。

分析:

對于的做法,首先我們排除特殊情況,不妨設,0<=l<=r,0<=s<=m。
顯然若存在一個的倍數滿足l<=sx<=r,那么此時的答案就是x。
若不存在,我們不妨將約束式改寫成代數式l<=s
x-my<=r。進一步改寫成以為y主元,即-r<=my-sx<=-l,再把它還原為取模的形式:(-r mod s)<=my mod s<=(-l mod s)。若能求出最小的滿足上式的y值,則可以求出唯一滿足上式的x值(因為區間中沒有s的倍數)。
所以我們只需要將讀入的四個數標準化,判斷是否存在簡單解以及判斷無解,假如需要的話遞歸調用函數,直至問題解決。

實現:

#include<cstdio>

long long t,m,s,l,r;
long long dg(long long m,long long s,long long l,long long r)
{
    if(l==0) return 0;
    if(l>=m || l>r || s%m==0) return -1;
    s%=m;
    long long x=(l-1)/s+1;
    if(x*s<=r) return x;
    long long y=dg(s,m,(-r%s+s)%s,(-l%s+s)%s);
    if(y==-1) return y;
    x=(r+m*y)/s;
    if(s*x-m*y>=l) return (x%m+m)%m;
    return -1;
}
int main()
{
    freopen("solve.in","r",stdin);freopen("solve.out","w",stdout);
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld%lld%lld",&m,&s,&l,&r);
        if(r>=m) r=m-1;
        printf("%lld\n",dg(m,s,l,r));
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容