【luoguP2371】 [国家集训队]墨墨的等式

题目链接

【luoguP2371】 [国家集训队]墨墨的等式

考虑将所有的(a_1x_1+a_2x_2+……+a_nx_n=B)(a_1)取模,那么所有可达到的B就分为了(0)~(a_1-1)

如果对(a_1)取模为(k)的一类(B)中最小的(B)(dis[k]),那么(dis[k]+a_1,dis[k]+a_1*2,……)都是可以取到的,

所以对于每一类求最短路,最后统计答案就行了

#include<iostream>
#include<cstring>
#include<cstdio>
#define int long long
using namespace std;

const int N=15;
const int M=500010;
const int INF=0x3f3f3f3f;

int n,a[N],Bmin,Bmax,am=INF;
int dis[M],que[5000010],head,tail;
bool inque[M];

signed main()
{
	scanf("%lld%lld%lld",&n,&Bmin,&Bmax);
	for(int i=1;i<=n;++i)
		scanf("%lld",&a[i]),am=min(am,a[i]);
	memset(dis,0x3f,sizeof(dis));
	dis[0]=0;
	que[++tail]=0;
	while(head<tail){
		int u=que[++head];
		inque[u]=0;
		for(int i=1;i<=n;++i){
			int v=(u+a[i])%am;
			if(dis[v]>dis[u]+a[i]){
				dis[v]=dis[u]+a[i];
				if(!inque[v]){
					que[++tail]=v;
					inque[v]=1;
				}
			}
		}
	}
	int ans=0;
	for(int i=0;i<am;++i)
	  if(dis[i]<=Bmax){
		ans+=(Bmax-dis[i])/am+1;
		if(dis[i]<Bmin)
			ans-=(Bmin-1-dis[i])/am+1;
	}
	printf("%lld
",ans);
	return 0;
}