CodeForces 1500B Two chandeliers
D. Two chandeliers
题意
给两个数组代表花的颜色,如果同一天花的颜色不同(数组下标循环),老板就会生气,求多少天后老板会生气\(k\)次
\(1 \leq k \leq 10^{12}\)
sol
容易知道一个循环为 \(lcm(n,m)\),所以可以先考虑求出一个循环中老板不生气的时间,然后找 \(k\) 就行
设 \(g\) 为 \(gcd(n,m)\) 则满足老板不生气的条件为 \(a_i = a_j\) 且 \(i \mod\ g = j \mod \ g\)
整理以下即为 ,\(x\equiv i(mod\ n)\) 且 \(x\equiv j(mod\ m)\)
对于上述两个式子,则有:
\[x = i + k_1*n
\]
\[x = j + k_2*m
\]
合并:
\[k_1*n+i = k_2 * m + j
\]
\[k_1*n-k_2*m=j-i
\]
这样可以通过\(Exgcd\) 得到一组解,\(x_1,y_1\) 满足\(k_1*n+(-k_2)*m=g\)
设 \(d\) 为\(j-i\) :
\[k_1*d/g*n+(-k_2)*d/g*m=g*d/g
\]
则\(x_1 = x_1*d/g,y_1 = y_1*d/g\)
要求最小正整数解:
\(x1 = (x1\%(m/g)+(m/g))\%(m/g)\)
然后将\(x_1\) 带入 \(x = i + k_1*n\) 中求出 \(x\);
\(x\)即为这个循环中老板不生气的时间
- 也可以用\(CRT\) 求出上述式子中的最小整数解
至于求出最终的\(k\),可以二分答案,或者排序后记录当前和上一个的差值并判断是否包含\(k\)即可
code
#define int long long
const int maxn = 2e6 + 10;
int n,m,k;
int a[maxn],b[maxn],c[maxn],lcm1,d[maxn],cnt,x,y;
bool check(int mid) {
int ans = mid;
for(int i = cnt; i >= 1; i--) {
if(mid >= d[i]) {
ans -= (mid-d[i])/lcm1 +1;
}
}
return ans >= k;
}
int exgcd(int a,int b,int &x,int &y) {
if(b == 0) {
x = 1;
y = 0;
return a;
}
int g = exgcd(b,a%b,y,x);
y -= (a / b) * x;
return g;
}
int calc(int a1,int b1,int c1,int d1) {
int b = -b1;
int a = a1;
int c = d1 - c1;
int g = exgcd(a,b,x,y);
if(c % g) return -1;
b = abs(b);
x *= c / g;
x = (x % (b / g)+ (b / g)) % (b / g);
int ans = x * a1 + c1;
ans = (ans%lcm1 + lcm1) %lcm1;
return (ans == 0 ? lcm1 : ans);
}
void solve() {
// k;
cin >> n >> m >> k;
lcm1 = n * m / (__gcd(n,m));
for(int i = 1; i <= n; i++) {
cin >> a[i];
c[a[i]] = i;
}
for(int i = 1; i <= m; i++) {
cin >> b[i];
int p = c[b[i]];
if(p) {
int tmp = calc(n,m,c[b[i]],i);
if(tmp != -1) {
d[++cnt] = tmp;
}
}
}
int l = 0,r = 1e18;
while(l < r) {
int mid = (l+r)/2;
if(check(mid)) r = mid;
else l = mid+1;
}
cout << l << "\n";
}