墨墨的等式(equ)题解

本文介绍了如何解决寻找等式a1x1+a2y2+…+anxn=B存在非负整数解的问题。给定数列长度N、B的上下界BMin和BMax,以及数列{an},通过算法确定满足条件的B的个数。样例输入为N=2, BMin=5, BMax=10, an=[3, 5],样例输出为5。解决方案利用最短路算法和堆优化,找到每个a对应的最小k值,以确定解的存在性。" 124482004,9849913,2021年电子学会Python等级考试(三级)精选考题解析,"['Python', '开发语言', '电子学会python考级']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

输入

输入的第一行包含3个正整数,分别表示N、BMin、BMax分别表示数列的长度、B的下界、B的上界。
输入的第二行包含N个整数,即数列{an}的值。

输出

输出一个整数,表示有多少b可以使等式存在非负整数解。

样例输入

2 5 10
3 5

样例输出

5

提示

对于20%的数据,N≤5,1≤BMin≤BMax≤10。

对于40%的数据,N≤10,1≤BMin≤BMax≤10^6。

对于100%的数据,N≤12,0≤ai≤4*10^5,1≤BMin≤BMax≤10^12。

想法

  • 对于一个a1 a1*k+x=B存在整数解 则a1*(k+1)+x=B’依然存在整数解
  • 因此我们对于一个a1 如果求出0到a1-1所有数对应式子中最小的k就能求出所有整数解
  • 求k的方法 采用最短路的方法

算法

  • 与想法相同找出a值中最小的一个 将0到a1-1所有数转化成一个点
  • dijkstra+堆优化

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#define MAXN 400005
using namespace std;
typedef long long ll;
int N,a[15],tot,head[MAXN];
ll low,up,dist[MAXN],ans;
struct iNode
{
    int u,v,next;
    ll w;
}edge[MAXN<<1];
struct Node
{
    int pos;
    ll v;
    Node(){};
    Node(int _pos,ll _v){pos=_pos;v=_v;}
    bool operator<(const Node &rhs)const
    {
        return v>rhs.v;
    }
};
priority_queue<Node >heap;
inline void add(int u,int v,ll w)
{
    edge[tot].u=u,edge[tot].v=v,edge[tot].w=w,edge[tot].next=head[u],head[u]=tot++;
}
inline void put(int a)
{
    for (int i=head[a];i!=-1;i=edge[i].next)
    {
        if(dist[edge[i].v]==-1)
        {
            heap.push(Node(edge[i].v,dist[a]+edge[i].w));
        }
    }
}
inline void dijkstra()
{
    memset(dist,-1,sizeof(dist));
    dist[0]=0;
    put(0);
    int p;
    while(!heap.empty())
    {
        if(dist[heap.top().pos]!=-1)
        {
            heap.pop();
            continue;
        }
        p=heap.top().pos;
        dist[p]=heap.top().v;
        heap.pop();
        put(p);
    }
}
int main()
{
    //freopen("equ.in","r",stdin);
    //freopen("equ.out","w",stdout);
    memset(head,-1,sizeof(head));
    scanf("%d%lld%lld",&N,&low,&up);
    low-=1;
    for (int i=1;i<=N;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]<a[1])swap(a[i],a[1]);
    }   
    //sort(a+1,a+1+N);
    for (int i=0;i<a[1];i++)
        for (int j=2;j<=N;j++)
            add(i,(i+a[j])%a[1],(i+a[j])/a[1]);
    dijkstra();
    for (int i=0;i<a[1];i++)
    {
        if(dist[i]==-1)continue;
        ans+=max(0ll,(up-i)/a[1]-max(0ll,max((ll)(low-i)/a[1],dist[i]-1)));
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值