我真不想寫背景

我真不想寫背景


題目描述

某巨魔突然對等式很感興趣,他正在研究 a1x1+a2x2++anxn=B 存在非負整數解的條件。
他要求你編寫一個程序,給定 Nan 、以及 B 的取值範圍,求出有多少 B 可以使等式存在非負整數解。


輸入格式

輸入的第一行包含 3 個正整數,分別表示 NBMinBMax 分別表示數列的長度、B 的下界、B 的上界。
輸入的第二行包含 N 個整數,即數列 an 的值。


輸出格式

輸出一個整數,表示有多少 B 可以使等式存在非負整數解。


樣例輸入

2 5 10
3 5


樣例輸出

5


樣例解釋

對於 B=5 ,式子有 x1=0 ,x2=1
對於 B=6 ,式子有 x1=2,x2=0
對於 B=7 ,無解。
對於 B=8 ,式子有 x1=1 ,x2=1
對於 B=9 ,式子有 x1=3 ,x2=0
對於 B=10 ,式子有 x1=0 ,x2=2


數據範圍

20% 的數據,N51BMinBMax10
40% 的數據,N101BMinBMax106
100% 的數據,N120ai41051BMinBMax1012


Solution

因爲 B 的範圍很大,所以我們考慮將其取模。
對於模 a1 的完全剩餘系中的每一個元素 y ,若能找到最小的能夠表示爲

m=i=2naixi
m mod a1=y
m ,則對於範圍內的任意一個與 y 關於模 a1 同餘的 B 都滿足
B=ka1+m

則對於每一個 y ,可以算出範圍內的與 y 關於模 a1 同餘的 B 的個數爲
bmaxma1Max(bminma1,0)+1

那麼,如何求出 m 呢?
my(moda1)

my=ka1

i=2naixika1=y

現已知 y1 ,枚舉 ak ,則可以更新 (y1+ak) mod a1
fi 表示 i 所對應的 m 要變成 i 需要減去多少個 a1
f(y1+ak) mod a1=fy1+((y1+ak)((y1+ak) mod a1)a1)

這就是一個最短路模型,每次用 SPFA 更新當前元素所能更新的元素。

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>

#define LL long long
#define Max(x,y) ((x)>(y)?(x):(y))

using namespace std;

LL n,bmi,bma,ans;
LL a[20],dis[400010];
bool in_stack[400010];
queue<LL>q;

void spfa(){
    memset(dis,-1,sizeof dis);
    dis[0]=0;q.push(0);in_stack[0]=true;
    while(!q.empty()){
        LL now=q.front();
        q.pop();in_stack[now]=false;
        for(LL i=2;i<=n;i++){
            LL tmp=now+a[i],qq=0;
            while(tmp>a[1]){
                tmp-=a[1];
                qq++;
            }
            if(dis[tmp]==-1||dis[tmp]>dis[now]+qq){
                dis[tmp]=dis[now]+qq;
                if(!in_stack[tmp]){
                    in_stack[tmp]=true;
                    q.push(tmp);
                }
            }
        }
    }
}

int main(){

    freopen("wth.in","r",stdin);
    freopen("wth.out","w",stdout);

    scanf("%lld%lld%lld",&n,&bmi,&bma);
    for(LL i=1;i<=n;i++)scanf("%lld",&a[i]);

    sort(a+1,a+n+1);

    spfa();
    for(LL i=0;i<a[1];i++)if(dis[i]!=-1){
        LL tmp=i+dis[i]*a[1];
        if(tmp>bma)continue;
        ans+=(bma-tmp)/a[1]-Max((LL)(ceil(((double)bmi-tmp)/a[1])),0)+1;
    }
    printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章