bzoj2118 墨墨的等式

Description

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

Input

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

Output

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

Sample Input

2 5 10
3 5

Sample Output

5

HINT

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

 

最短路。

终于会用堆优化的dijkstra了,STL中的priority_queue默认的是大根堆,为此debug两小时,然后重新看别人博客学了一下才知道人家是默认大根堆。。

找出a1到an中的最小值p,则如果可以构造出答案x,就可以构造出答案x+p

对于每个余数x(mod p),计算出最小的可以被构造出来的余数为x的数

根据余数建点,根据a[i]的值加边。

 

加边部分代码+注释:

for(int i=1;i<=n;++i) {
	a[i]=read();
	if(a[i]>bmax||!a[i]) i--,n--;//0或大于bmax的a[i]是没有用的
}
sort(a+1,a+n+1);
n=unique(a+1,a+n+1)-(a+1);//排序、去重
ll x;p=a[1];f[0]=1;//f为bool数组,f[x]=1表示余数为x的最小a[i]已经用于加边了
if(p==1) {
	printf("%lld",bmax-bmin+(ll)1);
	return 0;
}
for(int i=2;i<=n;++i) {
	x=a[i]%p;
	if(f[x]) continue;//有更小的j(a[j]<a[i])使得a[j]≡a[i],不需要再用a[i]去加边
	f[x]=1;
	for(int j=0;j<p;++j) add(j,(j+x)%p,a[i]);
}

 

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
#define ll long long
const int maxn=15,maxs=5e5+10,maxm=maxn*maxs;
ll n,p;
ll a[maxn],bmin,bmax,ans=0;
bool f[maxs];

ll aa;char cc;
ll read() {
	aa=0;cc=getchar();
	while(cc<'0'||cc>'9') cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	return aa;
}

int fir[maxs],nxt[maxm],to[maxm],e=0;ll v[maxm];
void add(int x,int y,ll z) {
	to[++e]=y;nxt[e]=fir[x];fir[x]=e;v[e]=z;
}

struct pq{
	ll x,d;
	bool operator <(const pq& a) const{return d>a.d;}
};

priority_queue<pq> Q;
ll dis[maxs];
bool vis[maxs];
void dijkstra() {
	memset(dis,0x3f3f3f3f,sizeof(dis));
	dis[0]=0;
	ll x,y,z;
	Q.push((pq){0,0});
	while(!Q.empty()) {
		x=Q.top().x;Q.pop();
		if(vis[x]) continue;
		vis[x]=1;
		for(y=fir[x];y;y=nxt[y]) {
			z=to[y];
			if(dis[z]<=dis[x]+v[y]) continue;
			dis[z]=dis[x]+v[y];
			Q.push((pq){z,dis[z]});
		}
	}
}

ll get_ans(ll l,ll r,ll x) {
	return (r-l)/p+1;
}

int main() {
	n=read();bmin=read();bmax=read();
	for(int i=1;i<=n;++i) {
		a[i]=read();
		if(a[i]>bmax||!a[i]) i--,n--;
	}
	sort(a+1,a+n+1);
	n=unique(a+1,a+n+1)-(a+1);
	ll x;p=a[1];f[0]=1;
	if(p==1) {
		printf("%lld",bmax-bmin+(ll)1);
		return 0;
	}
	for(int i=2;i<=n;++i) {
		x=a[i]%p;
		if(f[x]) continue;
		f[x]=1;
		for(int j=0;j<p;++j) add(j,(j+x)%p,a[i]);
	}
	dijkstra();
	for(ll i=bmin;i<min(bmin+p,bmax+1);++i) {
		x=i%p;
		if(dis[x]>bmax) continue;
		ans+=get_ans(max(i,dis[x]),bmax,x);
	}
	cout<<ans;
	return 0;
}

  

给出对拍的rand:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<ctime>
using namespace std;
#define ll long long
const int n=10;
ll bmin,bmax;

int main() {
	srand((unsigned)time(NULL));
	cout<<n<<" ";
	bmin=((rand()%5)*(rand()%(int)2e3)*1e3+rand()%(int)1e4)*1e4+rand()%(int)1e4;
	bmax=bmin+rand();
	cout<<bmin<<" "<<bmax<<"\n";
	ll x;
	for(int i=1;i<=n;++i) {
		x=rand()%1000+(rand()%50)*3e3*(rand()%3);
		cout<<x<<" ";
	}
	cout<<"\n";
	return 0;
}

  

posted @ 2017-09-17 20:27  shixinyi  阅读(233)  评论(0编辑  收藏  举报