Codeforces Round 885 (Div. 2) C. Vika and Price Tags

C. Vika and Price Tags

C - Vika and Price Tags

题意:

​ 初始两串数列\(a, b\),对于第\(i\)个数,令\(c_i=|a_i-b_i|\),然后将数列\(a=b,b = c\)。重复这样的操作,问是否可能让\(a\)串全部变成0。

思路:

这题实际上之前已经发过,但最近打牛客对这题有了新的理解,所以来记录一下。

​ 让我们假设\(a >> b\),那么我们模拟的过程就会变成如下这样:

\[(a, b)\rightarrow (b,a-b)\rightarrow (a-b,a-2b)\rightarrow (a-2b,b)\rightarrow (b,a-3b)\rightarrow (a-3b,a-4b)\rightarrow \\(a-4b,b)\rightarrow (b,a-5b)\rightarrow (a-5b,a-6b)\rightarrow (a-6b,b) \rightarrow (b,a-7b) \]

​ 仔细观察可以发现,\((a-kb,b)\)\((b,a-tb)\)的结构在反复出现,且\(k\)一定为偶数,\(t\)一定为奇数。

​ 对于这种一个数不断地减去另一个数的形式,我们可以回想起,裴蜀定理得,\(a,b\)辗转相减只可能得到其$gcd $的若干倍(gcd辗转相除的原理)

​ 也即是说,对于\((a,b)\)我们可以将其变成\((a\%b,b)/(b,a\%b)\),记\(t = a/ b\)

​ 对于\(t\)为奇数,\((a,b)\rightarrow(b,a \% b)\),次数为\((t - 1)/2 * 3 + 1\)

​ 对于\(t\)为偶数,\((a, b) \rightarrow (a\%b,b)\),次数为\(t/2*3\)

int cal(int a, int b){
    if(a == 0){
        return 0;
    }
    else if(b == 0){
        return 1;
    }
    if(a >= b){
        int t = a / b;
        if(t % 2){
            return cal(b, a % b) + 1 + (t - 1) / 2 * 3;
        }
        else{
            return cal(a % b, b) + t / 2 * 3;
        }
    }
    else{
        return 1 + cal(b, abs(a - b));
    }
}
 
void QAQ(){
    int n;
    cin >> n;
    vector<int> a(n + 1), b(n + 1);
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 1; i <= n; i ++) cin >> b[i];
    set<int> s;
    for(int i = 1; i <= n; i ++){
        if(a[i] == 0 && b[i] == 0) continue;
        s.insert(cal(a[i], b[i]) % 3);
    }
    if(s.size() <= 1) cout << "YES" << endl;
    else cout << "NO" << endl;
}

裴蜀定理得,\(a,b\)辗转相减只可能得到其$gcd $的若干倍(gcd辗转相除的原理)

posted @ 2023-08-05 20:24  一棵木头罢辽  阅读(61)  评论(0)    收藏  举报