牛客寒假第一场补题

寒假第一场补题

C、兢兢业业之移

题意:给定一个\(n\times n\)\(01\)矩阵,其中有\(\frac{n^2}{4}\)\(1\),其余为\(0\),求如何将所有\(1\)移到左上角的一个\(\frac{n}{2}\times\frac{n}{2}\)的正方形区域中。

思路:对于每一个左上角的\(0\),用\(bfs\)找到最佳的\(1\)和最短路径,移动过去。

时间复杂度:\(O(n^4)\)

void solve()
{
    int n;
    cin >> n;
    vector<string> g(n);
    vector<vector<bool>> vis(n,vector<bool>(n,false));
    vector<array<int,4>> ans;
    
    for(int i = 0 ; i < n ; i ++) cin >> g[i];
    auto bfs = [&](int sx,int sy){
        queue<PII> q;
        vector<vector<PII>> pre(n,vector<PII>(n));
        vector<vector<int>> d(n,vector<int>(n,-1));
        d[sx][sy] = 0;
        q.push({sx,sy});
        
        while(q.size()){
            auto [x,y] = q.front();
            q.pop();

            if(g[x][y] == '1'){
                swap(g[x][y],g[sx][sy]);
                while(x != sx || y != sy){
                    auto [prex,prey] = pre[x][y];
                    ans.push_back({prex,prey,x,y});
                    x = prex, y = prey;                    
                }
                return;
            }
                
            for(int i = 0 ; i < 4 ; i ++){
                int nx = x + dx[i], ny = y + dy[i];
                if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
                if(d[nx][ny] != -1 || vis[nx][ny]) continue;
                d[nx][ny] = d[x][y] + 1;
                pre[nx][ny] = {x,y};
                q.push({nx,ny});
            }
        }
    };
    for(int i = 0 ; i < n / 2 ; i ++){
        for(int j = 0 ; j < n / 2 ; j ++){
            if(g[i][j] == '0')
                bfs(i,j);
            vis[i][j] = true;
        }
    }
    
    cout << ans.size() << endl;
    for(auto [a,b,c,d] : ans)
        cout << a + 1 << " " << b + 1 << " " << c + 1 << " " << d + 1 << endl;
//     for(int i = 0 ; i < n ; i ++) cout << g[i] << endl;
}

F、双生双宿之探

题意:给定一个长度为\(n\)的数组,求有多少个连续区间构成双生数组(区间内只有两个数,且数量相等)

思路

1、双生数组只能有两个值\(\Rightarrow\)找到所有最长的连续区间,且只有两个数\(\Rightarrow\)用双指针

2、双生数组中需要两个数数量相同\(\Rightarrow\)一个数记为\(1\),另一个数记为\(-1\),求前缀和后,重复出现的\(sum\)即为贡献\(\Rightarrow\)前缀和求和为\(0\)的区间个数(贡献)

时间复杂度:\(O(n\log n)\)

void solve()
{
    int n;
    int ans = 0;
    cin >> n;
    vector<int> a(n+1);
    for(int i = 1 ; i <= n ; i ++) cin >> a[i];
    int l = 1, r = 0;
    set<int> st;
    auto get = [&](int l,int r){
//         cout << l << " " << r << endl;
        vector<int> sum(n+1,0);
        int f = a[l];
        for(int i = l; i <= r ; i ++){
            if(a[i] == f) sum[i] = 1;
            else sum[i] = -1;
            sum[i] += sum[i-1];
        }
        map<int,int> cnt;
        cnt[0]++;
        for(int i = l ; i <= r ; i ++){
            ans += cnt[sum[i]];
            cnt[sum[i]] ++;
        }
    };
    while(l<=n&&r<=n){
        r++;
        st.insert(a[r]);
        if(st.size() == 1) continue;
        else if(st.size() == 3){
            get(l,r-1);
//             cout << l << " " << r - 1 << endl;
            st.clear();
            st.insert(a[r]);
            st.insert(a[r-1]);
            l = r - 1;
            while(a[l-1] == a[l]) l --;
        }
    }
    cout << ans << endl;    
}
posted @ 2025-02-04 23:22  xde_yt  阅读(19)  评论(0)    收藏  举报