bzoj2118: 墨墨的等式
越来越菜的yzh天天模拟赛被机房的大佬踩爆
然后晚上做题继续被bzoj踩爆
这个真神!
考虑取出系数中最小值,假设放在a1
那么对于任意一个数,都可以表示成 q*a1+p对吧
而我们又有这样一个显然的东西:假如x可以被表示,那么x+a1也一定可以表示
那么只需要对于每一个p维护最小的q就可以了,p的范围就是0~a[1]-1
n很小,可以跑一个类似最短路的东西,每次枚举每一个数进行更新
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int _=1e2; const int maxn=20; const int maxa=5*1e5+_; LL a[maxn]; int head,tail,list[maxa]; LL d[maxa];bool v[maxa]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n;LL L,R; scanf("%d%lld%lld",&n,&L,&R);L--; for(int i=1;i<=n;i++)scanf("%d",&a[i]); sort(a+1,a+n+1); head=1,tail=2;list[1]=0; memset(d,63,sizeof(d));d[0]=0; v[0]=true; while(head!=tail) { int x=list[head]; for(int i=2;i<=n;i++) { int y=(x+a[i])%a[1],dd=(x+a[i])/a[1]; if(d[y]>d[x]+dd) { d[y]=d[x]+dd; if(v[y]==false) { v[y]=true; list[tail]=y; tail++;if(tail==maxa-1)tail=1; } } } v[x]=false; head++;if(head==maxa-1)head=1; } LL ans=0; for(int i=0;i<a[1];i++) { LL fir=a[1]*d[i]+i; if(fir<=L)ans-=(L-fir)/a[1]+1; if(fir<=R)ans+=(R-fir)/a[1]+1; } printf("%lld\n",ans); return 0; }
pain and happy in the cruel world.