CodeForces 1500B Two chandeliers

D. 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";

}
posted @ 2021-03-16 18:45  EnthalpyDecreaser  阅读(68)  评论(0编辑  收藏  举报