2023河南萌新联赛第(一)场:河南农业大学

打比赛千万千万千万不要上头(来自因死磕数论A题两小时而痛失两道最短路(压根连题面都没读)最终五题结尾的蒟蒻的赛后反思)

A.你也喜欢数学吗

真的一点都不喜欢数学好吧

先打表找规律,(找了二十分钟发现的规律,写了两小时最后发现只能过38%就离谱)

佬们说一眼看出来是k * (k + 1) * (k + 2) / 6, 不晓得楞个看出来的

不过即使看出来,也要先处理k,、k + 1和k + 2,不然会爆long long

冗长而难以理解的代码如下

#include <iostream>

using namespace std;

typedef unsigned long long ll;

const int mod = 1000000007;
ll ans;

ll quick_mul(ll a, ll b, ll mod)
{
    ll res = 0;
    
    while(b)
    {
        if(b & 1)
        {
            res += a;
            res %= mod;
        }
        
        a <<= 1;
        a %= mod;
        b >>= 1;
    }
    
    return res;
}

int main()
{
    ll k, x, y, z;
    scanf("%lld", &k);
    
    x = k, y = k + 1, z = k + 2;
    
    if(x % 2 == 0)
    {
        x /= 2;
    }
    else if(y % 2 == 0)
    {
        y /= 2;
    }
    
    if(x % 3 == 0)
    {
        x /= 3;
    }
    else if(y % 3 == 0)
    {
        y /= 3;
    }
    else
    {
        z /= 3;
    }
    
    ans = quick_mul(quick_mul(x, y, mod), z, mod);
    
    printf("%lld", ans);
    return 0;
}

E.动物朋友

前缀和+二分(ps:记得开long long, 不然会像我一样WA5发不知道哪错了)

循环遍历每一点

二分搜索从当前点开始是否存在连续的符合题意的区间,如果连续,则对于该区间的左端 l , 右端 r 有: 

s[r] - s[l - 1] == m (s为前缀和数组)

#include <iostream>

using namespace std;

const int N = 1e6 + 20;
int n, m, ans;
long long q[N], s[N];

bool check(long long x)
{
    int l = 0, r = n, mid;
    while(l <= r)
    {
        mid = l + r >> 1;
        if(s[mid] == x) return true;
        else if(s[mid] > x) r = mid - 1;
        else l = mid + 1;
    }
    return false;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i ++)
    {
        scanf("%lld",&q[i]);
        s[i] = s[i - 1] + q[i];
    }
    
    for(int i = 0; i < n; i ++)
    {
        if(check(s[i] + m))
        {
            ans ++;
        }
    }
    
    printf("%d",ans);
    
    return 0;
}

F.松鼠排序

枚举

依次从头枚举每个位置,若当前位置上坚果的大小与下标不同,则将该坚果交换至与其大小相同的下标处,重复上述操作直至当前位置上坚果大小与下标相同,枚举下一个位置

#include <iostream>

using namespace std;

const int N = 1e5 + 20;
int q[N];

int main()
{
    int n, ans = 0;
    scanf("%d",&n);
    
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d",&q[i]);
    }
    
    int i = 1;
    while(i < n)
    {
        while(q[i] != i)
        {
            swap(q[i], q[q[i]]);
            ans ++;
        }
        i ++;
    }
    
    printf("%d",ans);
    
    return 0;
}

G.Reverse

签到题(WA两发是怎么有脸说这是签到题的

要注意cnt > x时,先把x的值赋给y,不然就会像我一样WA两发(x表示最长连续的1的长度,y表示次长连续1的长度)

#include <iostream>
#include <string>

using namespace std;

string s;

int main()
{
    int n, x = 0, y = 0, cnt = 0;
    scanf("%d",&n);
    
    cin >> s;
    for(auto i : s)
    {
        if(i - '0')
        {
            cnt ++;
        }
        else
        {
            if(cnt > x)
            {
                y = x;
                x = cnt;
            }
            else if(cnt > y)
            {
                y = cnt;
            }
            cnt = 0;
        }
    }
    
    if(cnt > x)
    {
        y = x;
        x = cnt;
    }
    else if(cnt > y)
    {
        y = cnt;
    }
    
    printf("%d",x + y);
    
    return 0;
}

H.迷宫探险

最短路(bfs)

bfs模板套一下,不过要注意从发射器起跳时,发射器的落点与发射器到起点的距离相同

另外,注意从发射器跳到发射器的这种情况,check()函数用来处理这种情况

judge()函数用来判断边界问题(避免代码宽度过大,不方便查看)

#include <unordered_map>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>

using namespace std;

const int N = 3010;
typedef pair<int, int> PII;
unordered_map<int, int> mp;
queue<PII> q;

char g[N][N];
int n, m, d[N][N];

bool judge(int x, int f)
{
    if(f)
    {
        if(x >= 1 && x <= n) return true;
    }
    else
    {
        if(x >= 1 && x <= m) return true;
    }
    
    return false;
}

void check(int x, int y)
{
    int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
    for(int i = 0; i < 4; i ++)
    {
        int a = x + dx[i] * mp[x * 10000 + y], b = y + dy[i] * mp[x * 10000 + y];
        if(judge(a, 1) && judge(b, 0))
        {
            if(g[a][b] == '.' && d[a][b] == -1)
            {
                d[a][b] = d[x][y];
                q.push({a, b});
            }
            else if(g[a][b] == '*' && d[a][b] == -1)
            {
                d[a][b] = d[x][y];
                check(a, b);
            }
        }
    }
}

void bfs()
{
    memset(d, -1, sizeof(d));
    q.push({1, 1});
    
    int x, y, dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
    
    d[1][1] = 0;
    while(!q.empty())
    {
        PII t = q.front();
        q.pop();
        for(int i = 0; i < 4; i ++)
        {
            x = t.first + dx[i], y = t.second + dy[i];
            if(judge(x, 1) && judge(y, 0))
            {
                if(g[x][y] == '.' && d[x][y] == -1)
                {
                    d[x][y] = d[t.first][t.second] + 1;
                    q.push({x, y});
                }
                else if(g[x][y] == '*' && d[x][y] == -1)
                {
                    d[x][y] = d[t.first][t.second] + 1;
                    check(x, y);
                }
            }
        }
    }
}

int main()
{
    int k, x, y, z;
    scanf("%d%d",&n,&m);
    
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j <= m; j ++)
        {
            cin >> g[i][j];
        }
    }
    
    scanf("%d",&k);
    while(k --)
    {
        scanf("%d%d%d",&x,&y,&z);
        
        if(z)
        {
            mp[x * 10000 + y] = z;
        }
    }
    
    bfs();
    
    printf("%d",d[n][m]);
    
    return 0;
}

J.合唱比赛

农大竟然有合唱比赛,建议把高清视频发B站供我欣赏

区间左端点:我给它的分是最低分的时候, 此时最高分为题给最高分

区间右端点:我给它的分是最高分的时候, 此时最低分为题给最低分

综上,我压根无法左右比赛结果,我就是个菜狗,呜呜呜~

#include <iostream>

using namespace std;

int main()
{
    int n;
    double z, x = 0, y = 101, ans = 0;
    scanf("%d",&n);
    
    for(int i = 1; i <= n; i ++)
    {
        scanf("%lf",&z);
        
        ans += z;
        
        x = max(x, z);
        y = min(y, z);
    }
    
    printf("%lf %lf", (ans - x) / (n - 1), (ans - y) / (n - 1));
    
    return 0;
}

K.以撒和隐藏房间

枚举每一个点即可

注意题面要求是与三个普通房间相邻,不是至少三个

#include <iostream>
 
using namespace std;
 
const int N = 1010;
int n, m, g[N][N];
 
bool check(int x, int y)
{
     
     
    int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}, cnt = 0;
    for(int i = 0; i < 4; i ++)
    {
        if(x + dx[i] < 1 || x + dx[i] > n || y + dy[i] < 1 || y + dy[i] > m) continue;
        if(g[x + dx[i]][y + dy[i]] == 2) return false;
        if(g[x + dx[i]][y + dy[i]] == 1) cnt ++;
    }
     
    if(cnt == 3) return true;
    return false;
}
 
int main()
{
    bool f = 0;
    int ans = 0;
    scanf("%d%d",&n,&m);
     
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j <= m ; j ++)
        {
            scanf("%1d",&g[i][j]);
        }
    }
     
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j <= m; j ++)
        {
            if(g[i][j] == 0)
            {
                if(check(i, j))
                {
                    f = 1;
                    ans ++;
                }
            }
        }
    }
     
    if(f)
    { 
        puts("YES"); 
        printf("%d\n", ans);
    }
    else puts("NO");
     
    return 0;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值