我真不想写背景
题目描述
某巨魔突然对等式很感兴趣,他正在研究
a1x1+a2x2+…+anxn=B
存在非负整数解的条件。
他要求你编写一个程序,给定
N
、
输入格式
输入的第一行包含
3
个正整数,分别表示
输入的第二行包含
N
个整数,即数列
输出格式
输出一个整数,表示有多少 B 可以使等式存在非负整数解。
样例输入
2 5 10
3 5
样例输出
5
样例解释
对于
对于
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%
的数据,
N≤5
,
1≤BMin≤BMax≤10
。
40%
的数据,
N≤10
,
1≤BMin≤BMax≤106
。
100%
的数据,
N≤12
,
0≤ai≤4∗105
,
1≤BMin≤BMax≤1012
。
Solution
因为
B
的范围很大,所以我们考虑将其取模。
对于模
则对于每一个 y ,可以算出范围内的与
那么,如何求出 m 呢?
现已知 y1 ,枚举 ak ,则可以更新 (y1+ak) mod a1 :
设 fi 表示 i 所对应的
则
这就是一个最短路模型,每次用 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;
}