题意:
很长一大串的题意,可以化简为给定你两个序列,每个序列中都不会有重复的数,然后这两个序列都可以分别看做是可无限延伸循环的,然后给定你一个数字
k
k
k,
i
i
i从
1
1
1开始,问你
i
i
i到达多少后,前
i
i
i对
a
i
,
b
i
a_i,b_i
ai,bi中,有
k
k
k个位置
a
i
≠
b
i
a_i \neq b_i
ai=bi。
很明显影响
i
i
i因素是有多个位置他们的
a
i
=
b
i
a_i = b_i
ai=bi,假如对于一个值
v
a
l
val
val,它在
a
a
a中位置是
x
x
x,在
b
b
b中的位置时
y
y
y,那么也就是找到一个最小的位置pos使得
{
p
o
s
≡
x
(
m
o
d
n
)
p
o
s
≡
y
(
m
o
d
m
)
\begin{cases} pos \equiv x \ (mod \ n) \\pos \equiv y\ (mod \ m) \end{cases}
{pos≡x (mod n)pos≡y (mod m)
很明显这是个关于
p
o
s
pos
pos的同余方程,假如
n
n
n和
m
m
m互质那么可以直接
c
r
t
crt
crt解决,但是题目这里没要求,那么用
e
x
c
r
t
excrt
excrt也可解决,一般
e
x
c
r
t
excrt
excrt需要注意的细节我们也要注意。
再就是 k k k的范围太大了,但是题目要求我们找得到是等于 k k k的位置,也就是求一个最低的下限,很明显这个位置可以用二分去找出来,每次二分一个答案去检验,对应的值在当前位置区间内不相同的位置是否合法即可,尽量往小找。
用这个题可以学一下中国剩余定理和拓展中国剩余定理。
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
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
/************exCRT*************/
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]);//存的是相等的值出现的位置
}
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;
}