【bzoj2118】 墨墨的等式

http://www.lydsy.com/JudgeOnline/problem.php?id=2118 (题目链接)

题意

  给出B的取值范围[Bmin,Bmax],求方程a1x1+a2x2+…+anxn=B有多少B可以使等式存在非负整数解。

Solution

  问题很容易就被转化为:用a1,a2,a3,······an能组成多少个在范围[Bmin,Bmax]内的数。这是一类经典的图论问题。

  我们假设a[]中最小的元素为T,可以考虑用n个数能够组成的数对T的模的情况。用dis[i]表示构成的一个数Q,且Q mod T=i,Q是满足上述两个条件的最小值。我们在这里将题目中的区间改为具体的询问,更好的进行讨论,对于询问X,设X mod T=i,则有以下三种情况:

  1. dis[i]>x。由于用这n个数构成的一个模T为i的数,这个数的最小值为dis[i],而dis[i]>x,说明X是无法构成的。
  2. dis[i]=x。由于用这n个数构成的一个模T为i的数,这个数的最小值为dis[i],而dis[i]=x,说明X可以构成,且是能构成的模T等于i的最小的数。
  3. dis[i]<x。由于用这n个数构成的一个比X更小的 mod T为i的数Q,则X mod T=Q mod T,且X必定可以由Q加上若干个T得到,因此,X也是可以构成的。

  由上述三点可知,当dis[i]<=X时,X是可以被构成的,否则则不能。

  现在的问题是如何求解dis数组?

  相信各位看官已经发现dis数组的命名有点诡异,没错就是用最短路求解。由于dis[i] mod T=i,i的范围在0~T-1内,因此可以建立T个点0,1,2,······,T-1。对于点i和任意一个数a[j],设k=(i+a[j]) mod T,可以认为从i到k连条边权为a[j]的边,表示可以从 mod T=i这个点,通过加上边权a[j],到达 mod T=k的点。由于T mod T=0,即可设T为数字编号为0的点。要求X是否能由n个数构成,就要求出dis[X mod T]的最小值了;当X大于等于dis[X mod T],它就能够由着n个数构成,设X mod T=j,dis[j]即为j这个店到达0点的最短距离,它可以由0点直接加边权a[j]得到,也可以经过其他中间点到达。转换后,它就是个最短路问题了。

  再回到这个问题上。于是我们先建图,跑一遍最短路,预处理出dis数组,然后枚举i=0~T-1,计算模T为i的数在区间[Bmin,Bmax]中有多少个,统计答案即可。

细节

  堆里面又忘记开long long了,尴尬。

代码

// bzoj2118
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define MOD 10007
#define inf (1ll<<60)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=500010;
struct edge {int to,next,w;}e[maxn*10];
struct data {
	LL num,w;
	friend bool operator < (const data a,const data b) {
		return a.w>b.w;
	}
};
int head[maxn],a[maxn],vis[maxn];
int n,cnt;
LL L,dis[maxn],R;

void link(int u,int v,int w) {
	e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;
}
void Dijkstra() {
	priority_queue<data> q;
	for (int i=0;i<a[1];i++) dis[i]=inf;
	data x=(data){0,0},y;
	dis[0]=0;
	q.push(x);
	while (!q.empty()) {
		x=q.top();q.pop();
		if (vis[x.num]) continue;
		vis[x.num]=1;
		for (int i=head[x.num];i;i=e[i].next)
			if (dis[e[i].to]>x.w+e[i].w) {
				y.w=dis[e[i].to]=x.w+e[i].w;
				y.num=e[i].to;
				q.push(y);
			}
	}
}
int main() {
	scanf("%d%lld%lld",&n,&L,&R);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	if (!a[n]) return printf("0"),0;
	for (int i=0;i<a[1];i++)
		for (int j=2;j<=n;j++) link(i,(a[j]+i)%a[1],a[j]);
	Dijkstra();
	LL ans=0;
	for (int i=0;i<a[1];i++) if (dis[i]<=R) {
			LL l=max(0ll,(L-dis[i])/a[1]);
			if (l*a[1]+dis[i]<L) l++;
			LL r=(R-dis[i])/a[1];
			if (r*a[1]+dis[i]>R) r--;
			ans+=r-l+1;
		}
	printf("%lld\n",ans);
	return 0;
}

  

时间: 2024-11-25 07:17:40

【bzoj2118】 墨墨的等式的相关文章

bzoj2118 墨墨的等式

2118: 墨墨的等式 Time Limit: 10 Sec  Memory Limit: 259 MB Description 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+-+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N.{an}.以及B的取值范围,求出有多少B可以使等式存在非负整数解. Input 输入的第一行包含3个正整数,分别表示N.BMin.BMax分别表示数列的长度.B的下界.B的上界.输入的第二行包含N个整数,即数列{an}的值. Output 输出一个

BZOJ2118墨墨的等式[数论 最短路建模]

2118: 墨墨的等式 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1317  Solved: 504[Submit][Status][Discuss] Description 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N.{an}.以及B的取值范围,求出有多少B可以使等式存在非负整数解. Input 输入的第一行包含3个正整数,分别表示N.BMin.BMax分别表示数

【BZOJ 2118】 2118: 墨墨的等式 (最短路)

2118: 墨墨的等式 Description 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+-+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N.{an}.以及B的取值范围,求出有多少B可以使等式存在非负整数解. Input 输入的第一行包含3个正整数,分别表示N.BMin.BMax分别表示数列的长度.B的下界.B的上界.输入的第二行包含N个整数,即数列{an}的值. Output 输出一个整数,表示有多少b可以使等式存在非负整数解. Sample Input 2 5 1

BZOJ 2118: 墨墨的等式

2118: 墨墨的等式 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1656  Solved: 650[Submit][Status][Discuss] Description 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N.{an}.以及B的取值范围,求出有多少B可以使等式存在非负整数解. Input 输入的第一行包含3个正整数,分别表示N.BMin.BMax分别表示数

数论+spfa算法 bzoj 2118 墨墨的等式

2118: 墨墨的等式 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1283  Solved: 496 Description 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N.{an}.以及B的取值范围,求出有多少B可以使等式存在非负整数解. Input 输入的第一行包含3个正整数,分别表示N.BMin.BMax分别表示数列的长度.B的下界.B的上界.输入的第二行包含N个

2118: 墨墨的等式

2118: 墨墨的等式 https://www.lydsy.com/JudgeOnline/problem.php?id=2118 分析: 最短路. 题意就是判断[L,R]内多少数,可以被许多个a1,a2,a3...构成.设最小的Mi = min{ai}. 直接枚举肯定超时,那么换个方法枚举. 考虑一个能构成的数b,它一定可以分解为$b = k \times M_i + r, \ r<M_i$.而且$b + M_i$也是可以构成的.所以我们可以找到最小的%Mi=r的数,比它大的%Mi=r的数可以

[bzoj2118]墨墨的等式【dijk+堆】

编译器真是神经了  k=k*2打成了k*2居然都不报错  还一点事情没有 害我改一晚上 一开始忘记了c++的数组默认从0开始 后来又把dijk写T了.....重申一遍,这里是先把所有点加进去然后依次pop() 至于这道题,大家都说它是一道数论好题 而狗王一定要把它当作spfa专题来讲给小朋友们听 ---erh... 网上题解有很多 首推po姐的 #include<cstdio> #define ll long long #define inf 1<<29 #include<a

BZOJ 2118 墨墨的等式(最短路)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2118 [题目大意] 求a1x1+a2y2+…+anxn=B在B的取值范围,有多少B可以使等式存在非负整数解. [题解] 同余最短路,不等式解集计数即可. [代码] #include <cstdio> #include <algorithm> #include <queue> using namespace std; const int N=500010; n

BZOj 墨墨的等式(转化为最短路)题解

题意:中文题意不解释... 思路:这道题居然可以转化为最短路orz,要等式有非负整数解,我们可以转化一下:每个ai不限数量,问你能用ai数组拼出多少个Bmin~Bmax范围内的数,有点像完全背包的感觉,看怎样组合能拼出范围内的数. 我们找出ai中不为零的最小数记为p,如果我们把每个数进行操作ai%p ,那么所有的ai我们都可以用整数倍的p加上它的取模表示了.我们用dis[i]表示如果有一个数x:x%p == i,那么dis储存最小的x,也就是说dis储存着我们能用ai数组拼出的取模p等于i的最小