CF1501 D ---数论(excrt+二分)

Vasya is a CEO of a big construction company. And as any other big boss he has a spacious, richly furnished office with two crystal chandeliers. To stay motivated Vasya needs the color of light at his office to change every day. That’s why he ordered both chandeliers that can change its color cyclically. For example: red – brown – yellow – red – brown – yellow and so on.

There are many chandeliers that differs in color set or order of colors. And the person responsible for the light made a critical mistake — they bought two different chandeliers.

Since chandeliers are different, some days they will have the same color, but some days — different. Of course, it looks poor and only annoys Vasya. As a result, at the k-th time when chandeliers will light with different colors, Vasya will become very angry and, most probably, will fire the person who bought chandeliers.

Your task is to calculate the day, when it happens (counting from the day chandeliers were installed). You can think that Vasya works every day without weekends and days off.

Input
The first line contains three integers n, m and k (1≤n,m≤500000; 1≤k≤1012) — the number of colors in the first and the second chandeliers and how many times colors should differ to anger Vasya.

The second line contains n different integers ai (1≤ai≤2⋅max(n,m)) that describe the first chandelier’s sequence of colors.

The third line contains m different integers bj (1≤bi≤2⋅max(n,m)) that describe the second chandelier’s sequence of colors.

At the i-th day, the first chandelier has a color ax, where x=((i−1)modn)+1) and the second one has a color by, where y=((i−1)modm)+1).

It’s guaranteed that sequence a differs from sequence b, so there are will be days when colors of chandeliers differs.

Output
Print the single integer — the index of day when Vasya will become angry
cf题目

题目大意:
给定两串数,分别为n,m个,每组内无重复,大小均在[1,2*max(n,m)]内,每组数现在展开成无限个(首位相连)从两组第一个数开始一直向后遍历,求在第几个位置上满足,两组数不相同的位置等于k。

题解:
1.首先看两组内哪些数可以在一个LCM内相遇:
设数x在两组的位置(一个循环内)为p1,p2,当|p1-p2|%gcd(m,n)==0时,有相遇的可能。
2.现在求相遇的位置,满足mx+p1=ny+p2,即可用exgcd解出方程,但若m,n不互质,则需要用excrt(扩展中国剩余定理)解得出现的位置pos,然后对于每个数,在每个pos+k*LCM都会出现。
3.现二分答案,每次验证是否可行(遍历所有数看位置)复杂度(m+n),算法整体复杂度(m+n)logk

本来自己做的时候没有二分,就要一直遍历算每个数的每个出现位置,后来看了大佬的题解恍然大悟。。。。。

//中国剩余定理+二分
//在每个二分mid值遍历所有m和n,求出sum
//算法复杂度(m+n)logk
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define me(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int MAXN = 5e5 + 7;
ll n, m, k;
int p1[MAXN << 1], p2[MAXN << 1];//2 * max(n,m) 一个序列里面的数都不同保证了每一个数位置的唯一性
//crt
ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a % b);
}
ll exgcd(ll a, ll b, ll& x, ll& y) {
	if (b == 0) {
		x = 1, y = 0;
		return a;
	}
	else {
		ll res = exgcd(b, a % b, x, y);
		ll t = x;
		x = y;
		y = t - a / b * y;
		return res;
	}
}
ll excrt(ll m1, ll m2, ll a1, ll a2) {//解决模数不互质的情况
	ll x, y, c, g;
	c = a2 - a1;
	g = exgcd(m1, m2, x, y);
	x = x * c / g;//把方程右侧化为
	y = m2 / g;
	x = (x % y + y) % y;//求最小正整数解
	a1 = a1 + x * m1;
	m1 = m1 * m2 / g;
	return a1;//解x
}
ll crt[MAXN << 1], LCM;

bool check(ll x) {
	ll sum = 0, ma = 2 * max(n, m);
	for (int i = 1; i <= ma; i++) {
		if (!p1[i] || !p2[i]) continue;
		if (!crt[i] || x < crt[i]) continue;
		//x通解 x = x0 + lcm(m1,m2);
		sum += (x - crt[i]) / LCM + 1;//看看后面还有几个通解
		if (x - sum < k) return false;
	}
	return x - sum >= k;//总为x天,其中sum天相同,则x - sum天不同
}

int main() {
	scanf("%lld%lld%lld", &n, &m, &k);
	for (int i = 1, x; i <= n; i++) {
		scanf("%d", &x);
		p1[x] = i;
	}
	for (int i = 1, x; i <= m; i++) {
		scanf("%d", &x);
		p2[x] = i;
	}
	ll ma = 2 * max(n, m), g = gcd(n, m);
	for (int i = 1; i <= ma; i++) {//求解每一个值的最小出现的位置在哪
		if (!p1[i] || !p2[i]) continue;
		if (abs(p1[i] - p2[i]) % g != 0) continue;//不会相交(重合)
		crt[i] = excrt(n, m, p1[i], p2[i]);//存的是相等的值出现的位置
		//之后所有crt+k*LCM的位置都会出现
	}
	LCM = n * m / g;
	ll l = 1, r = ma * k, ans;//ma * k就是相等比较多的极端情况
	while (l <= r) {
		ll mid = (l + r) >> 1;
		if (check(mid)) {
			ans = mid;
			r = mid - 1;
		}
		else l = mid + 1;
	}
	printf("%lld\n", ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值