tech pack 1.

收录技巧题

1. CF1973E - Cat, Fox and Swaps

tag:构造、贪心;link

可以发现有一个通过元素 \(z\) 交换 \(x,y\) 的方法(不妨 \(x<y\)):

\((x,y,z)\to (z,y,x)\to(y,z,x)\to(y,x,z)\),需求是覆盖区间 \([x+z,y+z]\)

而可以通过交换 \((x,x+1),(x+1,x+2),...\) 的方式交换两个较远的数。所以不妨所有 \(p_i\neq i\) 的数都位于 \([le,ri]\) 之间,那么长度 \(=2\) 的合法 \([l,r]\) 应该满足 \(l\in[ri,le+n]\)

枚举区间长度,对于长度 \(i\),合法区间的 \(l\in[\max(1,ri-i+2),\min(ri,n+n-i)]\)

但是还需两个特判:

  • 不存在 \(p_i\neq i\),输出 \(n(2n+1)\) 即可。
  • 对于所有 \(p_i\neq i\)\(p_i+i+1\) 为一个定值 \(k\),这样区间 \([k,k]\) 也是合法的。注意到 \(k\in [ri,le+n]\),所以未统计的区间有且仅有一个,加上即可。
点击查看代码
//CF1973E
#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int T, n, p[N];

int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        bool flg = 1;
        int le = n + 1, ri = 0;
        for(int i = 1; i <= n; ++ i){
            scanf("%d", &p[i]);
            if(p[i] != i){
                flg = 0;
                le = min(le, i);
                ri = max(ri, i);
            }
        }
        if(flg){
            printf("%lld\n", n * 1ll * (n + n + 1));
        } else {
            long long ans = 0;
            int val = p[le] + le;
            for(int i = le; i <= ri; ++ i){
                if(p[i] != i && val != p[i] + i){
                    flg = 1;
                }
            }
            if(!flg){
                ++ ans;
            }
            swap(le, ri); 
            ri += n;
            for(int i = 2; i <= n + n; ++ i){
                ans += ri - le + 1;
                le = max(1, le - 1);
                ri = min(ri, n + n - i);
            }
            printf("%lld\n", ans);
        }
    }
    return 0;
}

2. CF1973D - Cat, Fox and Double Maximum

tag:复杂度分析;link

首先有两个方向:\(n\) 次询问问出 \(a_1\)\(n\) 次询问问出 \(\max\)。发现前面一种没什么前途,所以考虑后一种。设求出的 \(\max=p\),则答案只可能为 \(p\) 的倍数,设为 \(tp\)

又有 \(ktp=\sum f(l,r)\leq f(1,n)=np\),所以有 \(t\leq\dfrac nk\),对于任意一个 \(t\) 至多问 \(k\) 次,所以复杂度是正确的!!!

点击查看代码
//CF1973D
#include <bits/stdc++.h>
using namespace std;

int T, n, k, mx;

int ask(int l, int x){
    cout << "? " << l << ' ' << x << endl;
    int p;
    cin >> p;
    return p;
}
bool chk(int x){
    int tp = 1, cnt = 0;
    while(tp <= n){
        tp = ask(tp, x * mx) + 1;
        ++ cnt;
        if(cnt > k){
            return 0;
        }
    }
    return cnt == k && tp == n + 1;
}

int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &k);
        for(int i = n; i >= 1; -- i){
            if(ask(1, i*n) == n){
                mx = i;
                break;
            }
        }
        bool flg = 0;
        for(int i = n / k; i >= 1; -- i){
            if(chk(i)){
                flg = 1;
                cout << "! " << i * mx << endl;
                break;
            }
        }
        if(!flg){
            cout << "! -1" << endl;
        }
        int p;
        scanf("%d", &p);
    }
    return 0;
}
posted @ 2024-10-07 19:24  KiharaTouma  阅读(2)  评论(0编辑  收藏  举报