【国家集训队】墨墨的等式

墨墨突然对等式很感兴趣,他正在研究
a1x1+a2x2+...+anxn=B存在非负整数解的条件
他要求你编写一个程序 ,给定N、{an}、 以及B的取值范围
求出有多少B可以使等式存在非负整数解

集训队的神题……
怎么看都以为是数论题,结果是同余最短路……
通过对所有数%k,跑最短路,求出在%k意义下的最小数
那么在%k意义下的更大的数也一定可以抵达
而且有点卡常,所以跑spfa的时候不用建边,直接跑就好了
实乃思维神题啊……

代码:

#include
#define N 500005
#define inf (1LL<<60)
#define ll long long
using namespace std;

ll n,l,r,a[13],ans=0;

templateinline void read(T &res)
{
    char c;T flag=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
} 

ll dis[N];
bool vis[N];
queue q;
void spfa(int s)
{
    for(register int i=0;i<=a[1];++i) dis[i]=inf;
    memset(vis,0,sizeof(vis));
    q.push(s);
    dis[s]=0;
    vis[s]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;
        for(register int i=2;i<=n;++i)
        {
            int v=(u+a[i])%a[1];
            if(dis[v]>dis[u]+a[i])
            {
                dis[v]=dis[u]+a[i];
                if(!vis[v])
                {
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
}

int main()
{
    read(n);read(l);read(r);
    for(register int i=1;i<=n;++i) read(a[i]);
    sort(a+1,a+n+1);
    spfa(0);
    for(register int i=0;i=l) ans+=(r-dis[i])/a[1]+1;
            else ans+=(r-dis[i])/a[1]+1,ans-=(l-dis[i]+a[1]-1)/a[1];
        }
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(【国家集训队】墨墨的等式)