牛客小白月赛32

牛客小白月赛32

A. 拼三角
签到题,暴力DFS选C(6,3)即可,由于三个边有大小关系,前期排个序,可以利于后期三角形判别,选的三个数必定由小到大,a < b < c,只需判a+b > c即可。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 40;
const int N = 50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int m, n;
int a[6];
bool ans = 0;
int nums1[3], nums2[3];
bool vis[6];

bool judge( int p1, int p2, int p3 ){
    
    
    return p1+p2 > p3;
}

void dfs( int pos, int cnt ){
    
    
    if( ans ) return;
    if(cnt == 3 ){
    
    
        if( judge( nums1[0], nums1[1], nums1[2] ) ){
    
    
            int ct = 0;
            for( int i = 0; i < 6; i++ ){
    
    
                if( !vis[i] )
                    nums2[ct++] = a[i];
            }
            if( judge( nums2[0], nums2[1], nums2[2] ) )
                ans = 1;
        }
        return;
    }
    for( int i = pos+1; i < 6; i++ ){
    
    
        if( !vis[i] ){
    
    
            vis[i] = 1;
            nums1[cnt] = a[i];
            dfs( i, cnt+1 );
            vis[i] = 0;
        }
    }
}

int main( ){
    
    
    int t;
    scanf( "%d", &t );
    while( t-- ){
    
    
        ans = 0;
        for( int i = 0; i < 6; i++ )
            scanf( "%d", a+i );
        sort( a, a+6 );
        dfs( -1, 0 );
        if( ans ) printf( "Yes\n" );
        else printf( "No\n" );
    }
    return 0;
}

B. 相对分子质量
比赛的时候题目没看清题目,没看到有括号,浪费了一点时间,很常规的运算式处理。用栈维护括号的计算顺序即可。唯一需要考虑的就是入栈的顺序问题。当一个元素完整出现的时候马上入栈;但后面出现顺序的时候,栈顶元素弹出来,乘系数之后再入栈;当出现左括号的时候入栈-1做标记,当出现有括号的时候,不断弹出栈直到遇到左括号-1为止,计算括号内部运算式的和之后将和直接入栈。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 40;
const int N = 50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int m, n;
unordered_map<string,int> mp;

ll solve( string &s ){
    
    
    int len = s.length();
    string tmp = "";
    stack<int> sk;
    int i = 0;
    while( i < len ){
    
    
        if(s[i] >= 'A' && s[i] <= 'Z'){
    
    
            tmp = s[i++];
            while( s[i] >= 'a' && s[i] <= 'z' && i < len )
                tmp += s[i++];
            sk.push(mp[tmp]);
        }
        else{
    
    
            if( isdigit(s[i]) ){
    
    
                int num = 0;
                while( isdigit(s[i]) && i < len )
                    num = num*10+(s[i++]-'0');
                int tp = sk.top();
                sk.pop();
                sk.push(tp*num);
            }
            else if( s[i] == '('){
    
    
                sk.push(-1);
                i++;
            }

            else if( s[i] == ')'){
    
    
                ll cur = sk.top();
                sk.pop();
                ll tp = 0;
                while(cur != -1){
    
    
                    tp += cur;
                    cur = sk.top();
                    sk.pop();
                }
                sk.push(tp);
                i++;
            }
        }
    }
    ll ans = 0;
    while( !sk.empty( ) ){
    
    
        ans += sk.top();
        sk.pop();
    }

    return ans;
}


int main( ){
    
    
    string s;
    int x;
    while( scanf( "%d %d", &m, &n ) != EOF ){
    
    
        mp.clear();
        while( m-- ){
    
    
            cin >> s >> x;
            mp[s] = x;
        }
        while( n-- ){
    
    
            cin >> s;
            cout << solve(s) << endl;
        }
    }
    return 0;
}

C. 消减整数
很容易想到的贪心,先不断的乘2之后消减,余下的不能减的可以在中间步骤不乘2做减法,因此可以暴力的正着不重复的减一次,倒着可重复的补一次中间的不乘2做减法,这一步可以重复做,因此可重复减。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 40;
const int N = 30;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
ll m, n;
ll pw2[N];

void init( ){
    
    
    pw2[0] = 1;
    for( int i = 1; i < N; i++ )
        pw2[i] = pw2[i-1]<<1ll;
}


int main( ){
    
    
    int t;
    init();
    scanf( "%d", &t );
    while( t-- ){
    
    
        scanf( "%lld", &n );
        int cnt = 0;
        int i;
        for( i = 0; i < N; i++ ){
    
    
            if( n-pw2[i] >= 0 ){
    
    
                n -= pw2[i];
                cnt++;
            }
            else
                break;
        }
        for( ; i >= 0; i-- ){
    
    
            while( n-pw2[i] >= 0 ){
    
    
                n -= pw2[i];
                cnt++;
            }
        }
        
        printf( "%d\n", cnt );
    }
    return 0;
}

E.春游
贪心,哪个船人均消费少先优先安排人到哪个船。有剩下的人,懒得处理细节的可以做上下扰动处理,只有三人船和二人船,1. 若优先安排三人船,那可能会剩下零个人、一个人或者两个人,可以在原来的三人船中拆0或1或2条船人到剩下的人中重新组合成一批人,并把这批人分到二人船中;2. 若优先安排二人船,那可能会剩下零个人或一个人,可以在原来的二人船中拆0或1或2或3条到剩下的人当中重新组合成一批人,并把这批人分到三人船中。这些情况取最小值即可。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 40;
const int N = 30;
const int MOD = 1e9+7;
const ll INF = 1e18+50;
ll a, b, n;

int main( ){
    
    
    int t;
    scanf( "%d", &t );
    while( t-- ){
    
    
        scanf( "%lld %lld %lld", &n, &a, &b );
        ll ans = INF;
        if( a*3 <= b*2 ){
    
    
            ll num_2 = (n+1)/2;
            for( ll i = 0; i <= 3; i++ ){
    
    
                ll cur_2 = num_2-i;
                ll cur_3 = (n-cur_2*2+2)/3;
                ans = min( ans, a*cur_2+b*cur_3);
            }
        }
        else{
    
    
            ll num_3 = (n+2)/3;
            for( ll i = 0; i <= 2; i++ ){
    
    
                ll cur_3 = num_3-i;
                ll cur_2 = (n-cur_3*3+1)/2;
                ans = min(ans, a*cur_2+b*cur_3);
            }
        }
        printf( "%lld\n", ans );
    }
    return 0;
}

F. 五连珠
数位dp的思想,5*5的矩阵,5行每行5个数可以用5个二进制数表示,同理5列、主对角线、副对角线都可以分别用5个二进制表示。共12个数,每个位置的数可以用map映射,某行被消除时,对应的数会变成2^5-1=31,然后消除过程中判一下即可。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 40;
const int N = 30;
const int MOD = 1e9+7;
const ll INF = 1e18+50;
int m, n;


int main( ){
    
    
    int t;
    int at[12], bt[12];
    scanf( "%d", &t );
    while( t-- ){
    
    
        mem(at, 0);
        mem(bt, 0);
        map<int,pii> mpa;
        map<int,pii> mpb;
        int x;
        for( int i = 0; i < 5; i++ ){
    
    
            for( int j = 0; j < 5; j++ ){
    
    
                scanf( "%d", &x );
                mpa[x] = mk(i,j);
            }
        }
        for( int i = 0; i < 5; i++ ){
    
    
            for( int j = 0; j < 5; j++ ){
    
    
                scanf( "%d", &x );
                mpb[x] = mk(i,j);
            }
        }
        int up = 31;
        bool flaga = 0, flagb = 0;
        int ans = 0;
        for( int i = 0; i < 25; i++ ){
    
    
            scanf( "%d", &x );
            pii p = mpa[x];
            at[p.fi] += 1<<p.se;
            if( at[p.fi] == up )
                flaga = 1;
            at[5+p.se] += 1<<p.fi;
            if( at[5+p.se] == up )
                flaga = 1;
            if( p.fi == p.se ){
    
    
                at[10] += 1<<p.fi;
                if( at[10] == up )
                    flaga = 1;
            }
            if( p.fi+p.se == 4 ){
    
    
                at[11] += 1<<p.fi;
                if( at[11] == up )
                    flaga = 1;
            }
            
            p = mpb[x];
            bt[p.fi] += 1<<p.se;
            if( bt[p.fi] == up )
                flagb = 1;
            bt[5+p.se] += 1<<p.fi;
            if( bt[5+p.se] == up )
                flagb = 1;
            if( p.fi == p.se ){
    
    
                bt[10] += 1<<p.fi;
                if( bt[10] == up )
                    flagb = 1;
            }
            if( p.fi+p.se == 4 ){
    
    
                bt[11] += 1<<p.fi;
                if( bt[11] == up )
                    flagb = 1;
            }
            if( !ans && (flaga || flagb)){
    
    
                if( flaga && flagb )
                    ans = 0;
                else if( flaga )
                    ans = 1;
                else if( flagb )
                    ans = 2;
            }
        }
        printf( "%d\n", ans );
    }
    return 0;
}

G. 有始有终
基本思路是BFS,但中间电梯的处理需要注意一下,在每个位置都能建电梯,建完电梯后需要DFS处理出建完电梯后他所能联通的联通块(即电梯处能无限制的到达其上下左右四个点,而这四个点周围和他高度差不超过d的点也可直达),并将这些点重新入队列即可,每个没处理过的点都可以建电梯。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 35;
const int N = 35;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int m, n, sx, sy, ex, ey, d;
int mp[N][N], dis[N][N];
int dir[4][2] = {
    
    {
    
    1,0}, {
    
    -1,0}, {
    
    0,1}, {
    
    0,-1}};
pii vt[N*N];
int cnt;
queue<pii> q;

bool judge( int x, int y ){
    
    
    if( x >= 0 && y >= 0 && x < m && y < n && dis[x][y] == INF )
        return 1;
    return 0;
}

void dfs( int x, int y ){
    
    
    for( int i = 0; i < 4; i++ ){
    
    
        int tx = x+dir[i][0];
        int ty = y+dir[i][1];
        if( judge( tx, ty ) && abs(mp[x][y]-mp[tx][ty])<=d ){
    
    
            dis[tx][ty] = dis[x][y];
            q.push( mk(tx,ty) );
            dfs( tx, ty );
        }
    }
}

int main( ){
    
    
    int t;
    scanf( "%d", &t );
    while( t-- ){
    
    
        while( !q.empty() ) q.pop();
        scanf( "%d %d %d %d %d %d %d", &n, &m, &sy, &sx, &ey, &ex, &d );
        sx--, sy--, ex--, ey--;
        for( int i = 0; i < m; i++ ){
    
    
            for( int j = 0; j < n; j++ ){
    
    
                scanf( "%d", mp[i]+j );
                dis[i][j] = INF;
            }
        }
        q.push( mk(sx,sy) );
        dis[sx][sy] = 0;
        dfs( sx, sy );
        pii cur;
        while( !q.empty() && dis[ex][ey] == INF ){
    
    
            cnt = 0;
            while( !q.empty() ){
    
    
                vt[cnt++] = q.front();
                q.pop();
            }
            for( int k = 0; k < cnt; k++ ){
    
    
                cur = vt[k];
                for( int i = 0; i < 4; i++ ){
    
    
                    int tx = cur.fi+dir[i][0];
                    int ty = cur.se+dir[i][1];
                    if( judge( tx, ty ) ){
    
    
                        q.push( mk(tx, ty) );
                        dis[tx][ty] = dis[cur.fi][cur.se]+1;
                    }
                }
            }
            cnt = 0;
            while( !q.empty() ){
    
    
                vt[cnt++] = q.front();
                q.pop();
            }
            for( int k = 0; k < cnt; k++ ){
    
    
                cur = vt[k];
                for( int i = 0; i < 4; i++ ){
    
    
                    int tx = cur.fi+dir[i][0];
                    int ty = cur.se+dir[i][1];
                    if( judge( tx, ty ) ){
    
    
                        dis[tx][ty] = dis[cur.fi][cur.se];
                        q.push( mk(tx, ty) );
                        dfs( tx, ty );
                    }
                }
            }
        }
        printf( "%d\n", dis[ex][ey] );
    }
    return 0;
}

I. 螺旋矩阵
leetcode螺旋输出的逆操作,比较坑的是,样例和图片中的数字标号完全对不上(不看图的估计正确率还能高一点)。最基础的先要算出输出矩阵的宽和高,分四种情况:

  1. 宽=高(1)宽=高=偶数 (2).宽=高=奇数
  2. 高=宽-1 (1)宽为奇数,高为偶数 (2)宽为偶数,高为奇数

四种情况的起点和方向变化不同,分别处理一下即可。另外字符串安排在矩阵中的位置也是逆序的。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 800;
const int N = 800;
const int MOD = 1e9+7;
const ll INF = 1e18+50;
int m, n;
char mp[N][N];
bool vis[N][N];
int ex, ey;
int pos, len, sz;
string s;
int dir[4][4][2] = {
    
    {
    
    {
    
    -1,0}, {
    
    0,1}, {
    
    1,0}, {
    
    0,-1}},
                      {
    
    {
    
    0,-1}, {
    
    -1,0}, {
    
    0,1}, {
    
    1,0}},
                      {
    
    {
    
    1,0}, {
    
    0,-1}, {
    
    -1,0}, {
    
    0,1}},
                      {
    
    {
    
    0,1}, {
    
    1,0}, {
    
    0,-1}, {
    
    -1,0}}};


bool judge( int x, int y){
    
    
    if( x >= 1 && x <= m && y >= 1 && y <= n && !vis[x][y] )
        return 1;
    return 0;
}

int main( ){
    
    
    int t;
    scanf( "%d", &t );
    while( t-- ){
    
    
        mem( vis, 0 );
        cin >> s;
        len = s.length();
        sz = sqrt(len*1.0);
        if( sz*sz != len ) sz++;
        pos = sz*(sz-1);
        if( pos >= len )
            m = sz-1, n = sz;
        else
            pos = sz*sz, m=n=sz;

        int sx, sy;
        int flag = 0;
        if( !(m&1) && (n&1) ){
    
    
            flag = 0;
            sx = m, sy = 1;
        }
        if( (m&1) && (n&1) ){
    
    
            flag = 1;
            sx = m, sy = n;
        }
        if( (m&1) && !(n&1) ){
    
    
            flag = 2;
            sx = 1, sy = n;
        }
        if( !(m&1) && !(n&1) ){
    
    
            flag = 3;
            sx = 1, sy = 1;
        }

        if( pos > len )
            mp[sx][sy] = ' ';
        else
            mp[sx][sy] = s[pos-1];
        pos--;
        int tx = sx, ty = sy;
        vis[sx][sy] = 1;
        while( pos ){
    
    
            for( int i = 0; i < 4; i++ ){
    
    
                while( judge(tx+dir[flag][i][0], ty+dir[flag][i][1]) ){
    
    
                    tx += dir[flag][i][0];
                    ty += dir[flag][i][1];
                    vis[tx][ty] = 1;
                    if( pos > len )
                        mp[tx][ty] = ' ';
                    else
                        mp[tx][ty] = s[pos-1];
                    pos--;
                }
            }
        }
        for( int i = 1; i <= m; i++ ){
    
    
            for( int j = 1; j <= n; j++ )
                cout << mp[i][j];
            cout << endl;
        }
        cout << endl;
    }
    return 0;
}

J. 统计个数
N的范围只有200,T也只有50,C(N,3)的DFS暴力1e6左右,乘50不会爆。唯一坑的是,题目中关于三角形的定义描述真的是一言难尽,完全误导人的存在,和I题的图片坑比程度有的一拼。

代码

#include <bits/stdc++.h>
#define ll long long
#define mem( f, x ) memset( f, x, sizeof(f))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
#define pk push_back

using namespace std;
const int M = 205;
const int N = 205;
const int MOD = 1e9+7;
const ll INF = 1e18+50;
int m, n;
bool mp[N][N];
int num[3];
int ans1, ans2;
void dfs( int pos, int cnt ){
    
    
    if( cnt == 3 ){
    
    
        int a = num[0], b = num[1], c = num[2];
        if( mp[a][b] && mp[b][c] ){
    
    
            ans2++;
            if( mp[a][c] )
                ans1++;
        }
        if( mp[b][c] && mp[c][a] ){
    
    
            ans2++;
            if( mp[a][b] )
                ans1++;
        }
        if( mp[c][a] && mp[a][b] ){
    
    
            ans2++;
            if( mp[b][c] )
                ans1++;
        }
        return;
    }
    for( int i = pos+1; i <= n; i++ ){
    
    
        num[cnt] = i;
        dfs( i, cnt+1 );
    }
}

int gcd( int x, int y ){
    
    
    return !y ? x:gcd(y,x%y);
}
int main( ){
    
    
    int t;
    scanf( "%d", &t );
    while( t-- ){
    
    
        mem( mp, 0 );
        scanf( "%d %d", &n, &m );
        int x, y;
        for( int i = 0; i < m; i++ ){
    
    
            scanf( "%d %d", &x, &y );
            mp[x][y] = mp[y][x] = 1;
        }
        ans1 = ans2 = 0;
        dfs( 0, 0 );
        int gd = gcd(ans2, ans1);
        ans1 /= gd, ans2 /= gd;
        printf( "%d/%d\n", ans1, ans2 );
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42038564/article/details/115149129