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
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; }
弱者就是会被欺负呀