牛客小白月赛99 C~E

nannandbk / 2024-10-13 / 原文

牛客小白月赛99 C~E

C-迷宫

思路:其实能不能到达,只要看起点和终点是否能变成连通的。射线技能只能用一次,我们在起点能到的点\((x,y)\)\(check:x,y,x-1,y-1,y+1\)是否在终点能到达的点的坐标中出现。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e3 + 10;
int n,m; 
char a[N][N];
int ds[N][N],de[N][N];
bool vis[N][N];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
bool in(int x,int y)
{
    return x >= 1 && x <= n && y >= 1 && y <= m;
}

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    cin>>n>>m;
    int sx,sy,ex,ey;
    for(int i = 1;i <= n; i++)
    {
        for(int j = 1;j <= m; j++)
        {
            cin>>a[i][j];
            if(a[i][j]=='S')
                sx = i,sy = j;
            if(a[i][j]=='E')
                ex = i,ey = j;
        }
    }


    queue<array<int,3>>q;
    memset(ds,127,sizeof(ds));
    memset(vis,false,sizeof(vis));
    ds[sx][sy] = 0;
    q.push({sx,sy,0});
    vis[sx][sy] = true;
    while(!q.empty())
    {
        auto [x,y,d] = q.front();
        q.pop();

        for(int i = 0;i < 4; i++)
        {
            int dx = x + dir[i][0];
            int dy = y + dir[i][1];
            if(in(dx,dy) && a[dx][dy] != '#' && !vis[dx][dy]){
                vis[dx][dy] = true;
                q.push({dx,dy,d+1});
                ds[dx][dy] = d + 1;
            }

        }

    }

    vector<array<int,2>>vs;
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++)if(ds[i][j] < (1<<30)){
                vs.push_back({i,j});
                // cout<<"i = "<<i<<" j = "<<j<<"\n";
        }
 
    memset(de,127,sizeof(de));
    memset(vis,false,sizeof(vis));
    de[ex][ey] = 0;
    q.push({ex,ey,0});
    vis[ex][ey] = true;
    while(!q.empty())
    {
        auto [x,y,d] = q.front();
        q.pop();

        for(int i = 0;i < 4; i++)
        {
            int dx = x + dir[i][0];
            int dy = y + dir[i][1];
            if(in(dx,dy) && a[dx][dy] != '#' && !vis[dx][dy]){
                vis[dx][dy] = true;
                q.push({dx,dy,d+1});
                de[dx][dy] = d + 1;
            }

        }

    }


    set<int>x,y;
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++)if(de[i][j] < (1<<30)){
                // cout<<"i = "<<i<<" j = "<<j<<"\n";

                x.insert(i);
                y.insert(j);
        }

    bool ok = false;
    for(auto [i,j] : vs){
        if(x.find(i) != x.end())
            ok = true;
        if(i-1>=1 && x.find(i-1) != x.end())
            ok = true;
        if(i+1<=n && x.find(i+1) != x.end())
            ok = true;
        if(y.find(j) != y.end())
            ok = true;
        if(j-1>=1 && y.find(j-1) != y.end())
            ok = true;
        if(j+1<=m && y.find(j+1) != y.end())
            ok = true;
    }


    cout<<(ok?"YES":"NO")<<"\n";


    return 0;
}

D-又是一年毕业季

思路:如果眨眼时间是质数,那么它的倍数就都不可以。如果眨眼时间是合数,那么它分解出的最小质数就是答案。

那么我们去预处理出质数,然后找到第一个没出现过的质数就是答案。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 5e6 + 10;

int n;

ll tot, p[N], pr[N];
bool vis[N];
void prime(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!p[i])    p[i] = i, pr[++tot] = i; 
        for (int j = 1; j <= tot && pr[j] * i <= n; j++) {
            p[pr[j] * i] = pr[j];
            if(p[i] == pr[j])   break;
        }
    }
}


int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
  
    prime(N);
    int t; cin>>t;
    while(t--)
    {
        cin>>n;
        vector<int>v;
        for(int i = 1;i <= n; i++)
        {
            ll x; cin>>x;
            if(x > 5e6)continue;
            vis[x] = true;
            v.push_back(x);
        }

        for(int i = 1;i <= tot; i++)
        {
            if(!vis[pr[i]])
            {
                cout<<pr[i]<<"\n";
                break;
            }
        }
        for(auto x : v)
            vis[x] = false;
        

    }


    return 0;
}

E-多米诺骨牌

思路:毫无疑问是用第一个能压倒它的去压倒是最优的。我们记录当前最高的,能压就压,如果在这之前最高的都不能压倒的话,下一块就作为第一块再往后算。最后去前m大的就行了。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int f[N];

struct ty
{
    int h,x;
}a[N];

bool cmp(int x,int y)
{
    return x > y;
}

bool cmp1(ty x,ty y)
{
    return x.x < y.x;
}

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    int t; cin>>t;
    while(t--)
    {
        int n,m; cin>>n>>m;
        for(int i = 1;i <= n; i++)
            cin>>a[i].h;
        for(int i = 1;i <= n; i++)
            cin>>a[i].x;

        sort(a+1,a+1+n,cmp1);
        int t = 1,mx = a[1].h+a[1].x;
        vector<int>ans;
        for(int i = 2;i <= n; i++)
        {
            if(mx >= a[i].x){
                t++;
                mx = max(mx,a[i].h+a[i].x);
            }else{
                ans.push_back(t);
                t = 1;
                mx = a[i].h + a[i].x;
            }
        }

        ans.push_back(t);

        sort(ans.begin(),ans.end(),cmp);

        ll res = 0;
        for(int i = 0;i < min(m,(int)ans.size());i++)
            res += ans[i];
        cout<<res<<"\n";
    }


    return 0;
}