您的位置:首页 > 其它

bzoj 2118 墨墨的等式

2015-11-16 10:38 162 查看
又是好一道数论题!令mn为a[1]~a
中数的最小值。很显然,如果x能被凑出来,x+mn也能被凑出来。所以我们只需要知道对于每一个x属于[0,mn),满足y%mn==x中最小的y,那么就能知道[1,R]中模mn等于x的数里能凑出来的个数。注意spfa的时候正无穷要大一点需要特殊处理一下a=0的情况,但是数据好像a!=0
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>

#define md
#define ll long long
#define inf 1000000000000000LL
#define eps 1e-8
#define N 500010
using namespace std;
int q
;
ll dis
;
bool vis
;
int mn,n;
int a[20];
void spfa()
{
	int h=0,w=1,x,y; q[1]=0; vis[0]=1; 
	while (h!=w)
	{
		h++; if (h>mn+5) h=1; x=q[h];
		for (int i=1;i<=n;i++)
		{
			y=(x+a[i])%mn;
			if (dis[y]>dis[x]+a[i])
			{
				dis[y]=dis[x]+a[i];
				if (!vis[y])
				{
					vis[y]=1;
					w++; if (w>mn+5) w=1; q[w]=y;
				}
			}
		}
		vis[x]=0;
	}
}
	
ll query(ll x)
{
	ll ans=0;
	for (int i=0;i<mn;i++)
		if (dis[i]<=x) ans+=(x-dis[i])/mn+1; 
	return ans;
}
		
	
int main()
{
	mn=(1e9);
	ll L,R;
	scanf("%d%lld%lld",&n,&L,&R);
	for (int i=1;i<=n;i++) { scanf("%d",&a[i]); if (a[i]==0) { i--; n--; continue;} mn=min(mn,a[i]);}
	for (int i=1;i<mn;i++) dis[i]=inf;
	spfa();
	printf("%lld\n",query(R)-query(L-1));
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: