首页 > 其他分享 >[NOI2018] 屠龙勇士

[NOI2018] 屠龙勇士

时间:2023-07-15 10:12:54浏览次数:34  
标签:gcd lambda NOI2018 register times equiv 屠龙 勇士 lld

题意

求解下列同余方程组,

\[\begin{cases} b_1 x \equiv a_1 \pmod{m_1} \\ b_2 x \equiv a_2 \pmod{m_2} \\ \dots \\ b_n x \equiv a_n \pmod{m_n} \\ \end{cases}\]

其中,\(n \leqslant 10^5, m_i \leqslant 10^8, lcm(m_i) \leqslant 10^{12}, a_i \leqslant 10^{12}, b_i \leqslant 10^6\)

Solution

不难发现,此方程组和exCRT模板有异曲同工之妙,尝试用相同的办法进行化简

考虑到exCRT的解产生的同余方程不带有前缀系数,考虑如下同余方程组,

\[\begin{cases} x \equiv a_1 \pmod{m_1} \\ bx \equiv a_2 \pmod{m_2} \\ \end{cases} \]

展开得,

\[k_1 \times b m_1 - k_2 \times m_2= a_1 b - a_2 \]

该式子左侧类似裴蜀定理, 则存在 \(\lambda_1, \lambda_2\) 满足 \(\lambda_1 \times b m_1 + \lambda_2 \times m_2= gcd(b m_1, m_2)\)

当 \(gcd(b m_1, m_2) \nmid a_1 b - a_2\) 时, 方程组无解.

当 \(gcd(b m_1, m_2) \mid a_1 b - a_2\) 时, 存在 \(k_1 , k_2\) 满足 \(k_1 \times b m_1 - k_2 \times m_2= a_1 b - a_2\).

则特解 \(x^* = \frac{a_1 b - a_2}{gcd(bm_1, m_2)} \times \lambda_1 \times m_1\), 根据CRT的相关内容,得到通解

\[x = \frac{a_1 b - a_2}{gcd(bm_1, m_2)} \ \lambda_1 \ m_1 + k_1 \cdot lcm(m_1, m_2) \]

考虑由多个同余方程组成的方程组,上面通解可表达成

\[x \equiv \frac{a_1 b - a_2}{gcd(bm_1, m_2)} \ \lambda_1 \ m_1 \pmod{lcm(m_1, m_2)} \]

由此,从原方程组中依次选出一个同余方程进行合并,显然不失一般性。

考虑第一组方程如何求解,显然存在 \(x \equiv 0 \pmod{1}\) ,可用于求解第一个同余方程。

Code

点击查看代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <cmath>

using namespace std;

const int N = 1e5 + 50;
typedef long long lld;

inline lld read() {
	register lld w = 0, f = 1;
	register char c = getchar();
	while (c > '9' || c < '0') {
		if (c == '-')  f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		w = w * 10 + c - '0';
		c = getchar();
	}
	return w * f;
}

multiset <lld> S;

int n, M;
lld m[N], a[N], b[N], atk[N];

inline lld gcd(lld a, lld b) {
	return !b ? a : gcd(b, a % b);
}

inline lld exgcd(register lld a, register lld b, lld &x, lld &y) {
	if (!b) {
		x = 1;
		y = 0;
		return a;
	}
	register lld d = exgcd(b, a % b, x, y);
	register lld tmp = x;
	x = y;
	y = tmp - a / b * y;
	return d;
}

inline lld mul(register lld a, register lld b, register lld p) {
	lld ans = 0;
	while (b) {
		if (b & 1)  ans = (ans + a) % p;
		a = (a + a) % p;
		b >>= 1;
	}
	return ans;
}

lld a1, m1;

int main() {
	int T = read();
	while (T--) {
		bool allone = 1;
		n = read(), M = read();
		S.clear();
		for (register int i = 1; i <= n; ++i)  a[i] = read();
		for (register int i = 1; i <= n; ++i) {
			m[i] = read();
			if (m[i] != 1)  allone = 0;
		}
		for (register int i = 1; i <= n; ++i)  atk[i] = read();
		for (register int i = 1; i <= M; ++i) {
			register lld x = read();
			S.insert(x);
		}

		for(int i = 1; i <= n; ++i) {
			auto u = S.upper_bound(a[i]);
			if(u != S.begin()) u--;
			b[i] = *u;
			S.erase(u);
			S.insert(atk[i]);
		}

		if (allone) {
			register lld maxa = 0;
			for (register int i = 1; i <= n; ++i)  maxa = max(maxa, (lld)ceil(1.0 * a[i] / b[i]));
			printf("%lld\n", maxa);
			continue;
		}

		a1 = 0;
		m1 = 1;
		for (register int i = 1; i <= n; ++i) {
			lld x, y;
			lld g = exgcd(mul(b[i], m1, m[i]), m[i], x, y);
			x = (x % m[i] + m[i]) % m[i];
			lld C = (a[i] - mul(b[i], a1, m[i]) + m[i]) % m[i];
			if (C % g != 0) {
				printf("-1\n");
				goto ed;
			}
			lld tmp = m[i] / g * m1;
			a1 = (a1 + mul(mul(C / g, x, m[i] / g), m1, tmp)) % tmp;
			m1 = tmp;
		}
		
		printf("%lld\n", a1);
		ed:;
	}
	return 0;
}

后记

最近写数学题全是bug

标签:gcd,lambda,NOI2018,register,times,equiv,屠龙,勇士,lld
From: https://www.cnblogs.com/abigjiong/p/17555646.html

相关文章

  • CF896E/洛谷 P4117 [Ynoi2018]五彩斑斓的世界/Welcome home, Chtholly
    分块。我们先来考虑修改对整块的影响。记值域为\(V=10^5\)。考虑对每一块维护\(V\)个集合\(S_1,S_2,\cdots,S_V\),第\(i\)个集合\(S_i\)维护了区间中所有\(=i\)的元素的一些信息,并维护区间的最大值\(m\),对于一次操作\(x\):若\(m\le2x\),我们暴力对每个\(i\in[x+1,......
  • [NOI2018] 你的名字
    给定串\(S,T_{1,\cdots,q}\),每次询问是\(S[l_i,r_i]\)的子串但不是\(T_i\)的子串的本质不同子串个数。\(|S|\le5e5,q\le1e5,\sum|T|\le1e6\)。我们先考虑\(l=1,r=|S|\)怎么做。显然我们使用SAM可以简单计算出\(T_i\)的本质不同子串数,那么我们肯定想算出来\(S\)......
  • 屠龙记
    我是一个正经的大龄c#程序员,突然接到了一个大数据报表需求,开发语言python,框架pyspark,脚本运行环境juypter.需求是这样的:工厂有很多生产线,每个生产线都有一套工序,每个工序都要扫码,我的任务就是得到工序之间的时间差,计算一个叫leadtime的指标,分析每条产线的哪个环节耗时比较多......
  • 真的勇士,才敢把文档命名为「最终版」
    前几天,年轻的同事在群里发了一个文档,名字叫「XXXX最终版」。大家一看就知道,未来一定还会出现——最终版-1最终版-2真最终版最终最终版绝对不再改版……再改我就死给你看版……所以,我的做法是,命名一般是按日期来,名称最后写一些关键信息:「20170525XXXX」「20170527XXXX评审后修改......
  • [NOI2018] 归程 解题报告
    题面步行的最小距离很容易求,dij随便求一下每个点的最短路,然后找到与\(v\)能相互坐车到达的点,对这些点的最短路都有可能是答案,取个\(\min\)即可。所以本题最大的问题是怎么找到在水位线为\(p\)时,与\(v\)能相互坐车到达的点。可以想到只保留海拔大于\(p\)的边,因为只要考......
  • 勇士召唤Summon Quest一款mac冒险游戏 中文版
    SummonQuest是一款卡牌收集类的手机游戏,玩家需要在游戏中收集各种强力的卡牌,并组建自己的队伍来进行战斗。游戏采用了即时战斗的方式,玩家需要根据卡牌的属性和技能来制定最佳策略,战胜对手。游戏特色:卡牌收集:SummonQuest拥有数百张不同类型的卡牌,每个卡牌都有独特的属性和技能,玩家......
  • [Ynoi2018] 天降之物
    [Ynoi2018]天降之物这个根号分治太神啦。首先考虑一个朴素的暴力:对每个数维护出现位置的std::vector这样查询可以两个指针遍历std::vector做到平方复杂度。注意到复杂度和出现次数有关,那么就可以考虑阈值分治了,然而合并的操作使得我们不好维护信息。先考虑不带修的情况,对......
  • 【NOI2018】冒泡排序
    【NOI2018】冒泡排序Description最近,小S对冒泡排序产生了浓厚的兴趣。为了问题简单,小S只研究对\(1\)到\(n\)的排列的冒泡排序。下面是对冒泡排序的算法描述。......
  • P4768 [NOI2018] 归程 题解
    这是一个悲伤的题目,自这道题后,\(\text{Noi}\)再无\(\text{SPFA}\)。首先讲一下重构树是啥。重构树是基于\(\text{kurskal生成树}\)算法的一棵树,对于每一次合并一条......
  • 【题解】P4768 [NOI2018] 归程(树上倍增,Kruskal 重构树,dijkstra)
    【题解】P4768[NOI2018]归程作为一道NOI的D1T1,放在现在或许难度不够(?),但可能在Kruskal重构树还未普及的当时,还是相对来说比较难的一道题吧。写篇题解记录一下。题......