女神训练赛 Round 02

棋盘问题

这题就是简单的搜索,类似八皇后问题,dfs 枚举每一行放在哪里一列,或者不放。在枚举的过程中直接筛掉之前放过的列。

#include <string>
#include <iostream>

using namespace std;

int  n , m , res;
bool v[15];
string g[15];

void dfs( int x , int t ){
    if( t == m ) {
        res++;
        return;
    }
    if( x == n ) return;
    dfs( x + 1 , t );
    for( int i = 0 ; i < n ; i ++ ){
        if( v[i] || g[x][i] == '.' ) continue;
        v[i] = 1 , dfs( x + 1 , t + 1 ) , v[i] = 0;
    }
    return;
}

void solve(){
    for( int i = 0 ; i < n ; i ++ ) cin >> g[i];
    fill( v , v + 15 , false );
    res = 0;
    dfs( 0 , 0 );
    cout << res << "\n";
}

int32_t main() {
    while(1){
        cin >> n >> m;
        if( n == m && n == -1 ) return 0;
        solve();
    }
}

Black Box

这套题的解法很多,这里讲一个我期望的做法,就是对顶堆。

我分别维护一个大根堆和一个小根堆。

比如这次的GET操作要求的是i,那么我就要保证大根堆中有i-1个数,且是最小的i-1个数,剩余的数都在小跟堆中。因为最小的i-1个数都在大根堆中,此时小根堆的堆顶就是第i小的数。

当每次i=i+1的时候我都把小根堆的堆顶移动到大根堆中,这样在下一次询问的时候答案依旧是小根堆的堆顶。

那么问题来了,小根堆很好理解,为了每次取出剩下的数中最小的一个。为什么是大根堆呢?

ADD操作的时候,如果x是大于第i-1小的数,显然直接插入到小根堆中就好了。但是如果x小于第i-1小的数,如果插入到小根堆中,就无法满足大根堆中是最小的i-1个数的性质了,所以此时前i-1小的数中最大的数放入到小跟堆中,在把x插入到大根堆中,才能满足大根堆中是最小的i-1个数。

上述的操作看起来很麻烦,其实是可以合并操作的,在ADD的时候,先把x插入到大根堆中,在把大根堆的堆顶移动到小根堆中就好。不明白为什么这样合并的自己模一下简单数据就懂了。

所以这样的话,每次插入和询问的操作复杂度都是\(O(\log n)\)的,整体的复杂度就是O(n\log n)

#include <iostream>
#include <queue>
using namespace std;

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
    return x * f;
}

const int N = 30005;
int a[N] , b[N];

priority_queue<int> l;// 大根堆
priority_queue<int , vector<int> , greater<int> > r;// 小根堆


int32_t main(){
    int n = read() , m = read() ;
    for( int i = 1 ; i <= n ; i ++ )
        a[i] = read();
    // i 第i次 GET 操作 , j表示时间,在 j 时间应该 ADD( a[j] )
    for( int i = 1 , j = 1 , x ; i <= m ; i ++ ){
        x = read();
        for( ; j <= x ; j ++ )
            l.push( a[j] ) , r.push( l.top() ) , l.pop();
        cout << r.top() << "\n";
        l.push( r.top() ) , r.pop();
    }
}

∵∴∵

这道其实算是签到题了,把两个字符串按照奇偶位置合并就好了

#include<bits/stdc++.h>

using namespace std;

int32_t main() {
    string a , b;
    cin >> a >> b;
    for( int i = 0 ; i < a.size() ; i ++ ){
        cout << a[i];
        if( i < b.size() ) cout << b[i];
    }
    return 0;
}

posted @ 2022-10-09 21:10  PHarr  阅读(20)  评论(0编辑  收藏  举报