bzoj 2118: 墨墨的等式

Description

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

Solution

选择任意一个正整数\(a_i\),作为 \(x*a_i\) 的底数,然后假如我们知道了最小满足 \(B \% a_i=k\)\(B\),那么大于 \(B\) 的满足与 \(B\) 同余的也一定能够凑出来
所以我们只需要对于每一个余数,求出 \(dis[i]\) 表示用 \(a_1....a_n\) 能够凑出的满足 \(B%a_i=i\) 的最小的 \(B\) 为多少
然后对于每一个剩余类,分别算答案即可,可以保证不重不漏
最后答案就是 \(solve(BMax)-solve(BMin-1)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=15;
int n,a[N],p=1;ll L,R,dis[500005];
queue<int>Q;bool vis[500005];
inline void spfa(){
	for(int i=0;i<a[p];i++)dis[i]=1e13;
	dis[0]=0;vis[0]=1;Q.push(0);
	while(!Q.empty()){
		int x=Q.front();Q.pop();
		for(int i=1;i<=n;i++){
			int u=(x+a[i])%a[p];
			if(dis[x]+a[i]<dis[u]){
				dis[u]=dis[x]+a[i];
				if(!vis[u])vis[u]=1,Q.push(u);
			}
		}
		vis[x]=0;
	}
}
inline ll calc(ll x,int k){
	return (x-k)/a[p]+1;
}
inline ll solve(ll mid){
	ll ret=0;
	for(int i=0;i<a[p];i++)
		if(dis[i]<=mid)ret+=calc(mid,i)-calc(dis[i]-1,i);
	return ret;
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%d%lld%lld",&n,&L,&R);
  for(int i=1;i<=n;i++)scanf("%d",&a[i]);
  sort(a+1,a+n+1);
  if(a[n]==0){puts("0");return 0;}
  while(!a[p])p++;spfa();
  printf("%lld\n",solve(R)-solve(L-1));
  return 0;
}

posted @ 2018-04-13 17:32  PIPIBoss  阅读(197)  评论(0编辑  收藏  举报