P2371 [国家集训队] 墨墨的等式

P2371 [国家集训队] 墨墨的等式

题目描述

墨墨突然对等式很感兴趣,他正在研究 ∑ i = 1 n a i x i = b \sum_{i=1}^n a_ix_i=b i=1naixi=b 存在非负整数解的条件,他要求你编写一个程序,给定 n , a 1 … n , l , r n, a_{1\dots n}, l, r n,a1n,l,r,求出有多少 b ∈ [ l , r ] b\in[l,r] b[l,r] 可以使等式存在非负整数解。

输入格式

第一行三个整数 n , l , r n,l,r n,l,r

第二行 n n n 个整数 a 1 … n a_{1\dots n} a1n

输出格式

一行一个整数,表示有多少 b ∈ [ l , r ] b\in[l,r] b[l,r] 可以使等式存在非负整数解。

输入输出样例 #1

输入 #1

2 5 10
3 5

输出 #1

5

说明/提示

对于 20 % 20\% 20% 的数据, n ≤ 5 n \le 5 n5 r ≤ 10 r \le 10 r10

对于 40 % 40\% 40% 的数据, n ≤ 10 n \le 10 n10 r ≤ 1 0 6 r \le 10^6 r106

对于 100 % 100\% 100% 的数据, n ≤ 12 n \le 12 n12 0 ≤ a i ≤ 5 × 1 0 5 0 \le a_i \le 5\times 10^5 0ai5×105 1 ≤ l ≤ r ≤ 1 0 12 1 \le l \le r \le 10^{12} 1lr1012

思路:

这个题代码倒不难写,就同余最短路的板题,但是公式不好推,判断这题用同余最短路和建边不太好推导。

∑ i = 1 n a i x i = b \sum_{i=1}^n a_ix_i=b i=1naixi=b

假设我们的 ∑ i = 1 n a i x i = t \sum_{i=1}^n a_ix_i=t i=1naixi=t 有一组非负整数解 { x 1 , x 2 , x 3 … … x n − 1 , x n } \{x_1,x_2, x_3……x_{n-1},x_n\} {x1x2x3……xn1xn},那我们必定能获得第其他组非负整数解的方法是什么呢?我们可以发现,当我加上 k k k a p ( p ∈ [ 1 , n ] ) a_p(p∈[1, n]) ap(p[1,n]) 的时候,一定会满足这个公式,因为就相当于 a p a_p ap 的系数加上了 k k k,也就是(假设 p = 1 p = 1 p=1 { x 1 + k , x 2 , x 3 … … x n − 1 , x n } \{x_1 + k,x_2, x_3……x_{n-1},x_n\} {x1+kx2x3……xn1xn}。所以我们就推出来了一个结论:
∑ i = 1 n a i x i = t + k × a p ( p ∈ [ 1 , n ] ) \sum_{i=1}^n a_ix_i=t + k×a_p(p∈[1, n]) i=1naixi=t+k×ap(p[1,n])
最后我们在计算结果的是 [ 0 , r ] − [ 0 , l − 1 ] = [ l , r ] [0, r] - [0, l - 1] = [l, r] [0,r][0,l1]=[l,r],因为我们同余最短路求出来的是 d i s t dist dist 同余组最小值,如果说 ( l − 1 ) > d i s t (l - 1) > dist (l1)>dist 的话我用 d i s t − ( l − 1 ) x + 1 \frac{dist - (l - 1)}{ x + 1} x+1dist(l1) 得到的就是我在范围 [ 0 , l − 1 ] [0, l - 1] [0,l1] d i s t + k × x dist + k ×x dist+k×x 能计算出的数的数量。 [ 0 , r ] [0, r] [0,r] 也同理, d i s t − r x + 1 \frac{dist - r}{x + 1} x+1distr。然后将两者相减得到 [ l , r ] [l, r] [l,r]。为什么一定要这么做呢,因为我这个同余最短路求出来的是满足同余组要求的最小值,如果说 l = 6 l = 6 l=6,而同余组余 1 1 1 的组(上界 x = 4 x = 4 x=4)结果是 5 5 5, 那我 5 5 5 就比 6 6 6 小,换句话说就是同余最短路求出来的数只与 m o d x mod x modx x x x 有关,不会被 l , r l,r lr约束,所以求出最小值还要去得到符合这个区间的数也就是 t + k × a p t + k×a_p t+k×ap ,但是挨个遍历如果 r 过大时间复杂度会过高,所以用前缀和的思想,求一遍范围在 [ 0 , l − 1 ] [0, l - 1] [0,l1] 里的,一遍 [ 0 , r ] [0, r] [0,r] 的,做差得到结果 [ l , r ] [l, r] [l,r] 的数量。

AC code:

#include <iostream>
#include <climits>
#include <limits>
#include <vector>
#include <queue>

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef std::pair<ll, ll> PII;

#define rep(i, n) for(ll i = 0; i < n; i++)
#define Rep(i, len, n) for(ll i = len; i < n; i++)
#define MAX_INT 0x7fffffff
#define MIN_INT 0x80000000

const ll INF = std::numeric_limits<ll>::max();

ll n, l, r, x = INF;
std::vector<std::vector<PII>> e;
std::vector<ll> a, dist;
std::vector<bool> vis;
std::priority_queue<PII, std::vector<PII>, std::greater<PII>> q;

inline void Dijkstra() {

	q.push({0, 0});
	dist[0] = 0;

	while(!q.empty()) {
		auto [val, u] = q.top();
		q.pop();
		if(vis[u]) continue;
		vis[u] = true;

		for(const auto&[v, w] : e[u]) {
			if(dist[v] > dist[u] + w) {
				dist[v] = dist[u] + w;
				q.push({dist[v], v});
			}
		}

	}
}

int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr), std::cout.tie(nullptr);
    
    std::cin >> n >> l >> r;
    a.resize(n);
    rep(i, n) {
    	std::cin >> a[i];
    	if(a[i] != 0)  x = std::min(x, a[i]);
    }
    dist.resize(x, INF);
    vis.resize(x, false);
    e.resize(x);

    rep(i, x) {
    	rep(j, n) {
    	 	// 自己不用跟自己建边
    		if(a[j] != x) e[i].push_back({(i + a[j]) % x, a[j]});
    	}
    }

    Dijkstra();

    ll ans_l = 0, ans_r = 0;
    rep(i, x) {
    	if(dist[i] <= (l - 1)) ans_l += ((l - 1) - dist[i]) / x + 1;
    	if(dist[i] <= r) ans_r += (r - dist[i]) / x + 1;
    }

    std::cout << ans_r - ans_l << '\n';
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值