牛客小白月賽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;
}