牛客小白月赛89

牛客小白月赛89

A.伊甸之花 

分析:若乐曲中同时存在1和m则无解,否则一定可以通过整体上移/下移一个音调来满足

#include<bits/stdc++.h>
using namespace std;
int n,m,f1,f2;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        if(x==1) f1=1;
        if(x==m) f2=1;
    }
    if(f1&&f2) cout<<"No"<<endl;
    else cout<<"Yes"<<endl;
    return 0;
}

B.显生之宙

分析:根据题意,设想一下要让结果最小,应该如何操作。很显然对于负数,把其他所有数都加上这个数,对于正数,只选择一个数增加。

然后为了让负数最大化利用,将数组从小到大排序,让最小的数放前面,就可以尽可能让更多的数加上这个负数。然后就是模拟前面说的这个操作的过程。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
int n;
ll a[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n);
        ll sum=0,ans=0;//sum记录需要减的负数之和
        for(int i=1;i<n;i++)
        {
            a[i]+=sum;
            if(a[i]>=0) ans+=a[i];
            else sum+=a[i];
        }
        cout<<ans+a[n]+sum<<endl;
    }
    return 0;
}

C.太阳之华

分析:观察样例,直接猜以下结论:开始全都是蓝,则直接后手赢,如果红能一步赢,则先手赢,否则肯定会僵持住,就是平局。(证明不来)

####红赢<---->红先手一步就能赢(因为红先下棋,红色+1,然后蓝下棋,蓝+1,如果红先手不能一步赢蓝,则会一直循环下去,即为平局)

所以这题主要代码考察如何判断红色一步直接赢,我的想法是这样:

用并查集把所有红色的连通块都缩在一起,统计选择每个连通块,能够增加的蓝色方块个数,若某个连通块该值等于场上所有蓝色方块个数,则可以一步先手赢。

#include<bits/stdc++.h>
using namespace std;
int n,m,T;
char s[2010][2010];
set<int> st;
bool vis[2010][2010];//判断该格子有没有被遍历过
void dfs(int x,int y)
{
    if(vis[x][y]) return; 
    vis[x][y]=true;
    int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
    for(int d=0;d<=3;d++)
    {
        int nx=x+dx[d],ny=y+dy[d];
        if(nx>0&&nx<=n&&ny>0&&ny<=m)
          {
                if(s[nx][ny]=='#') dfs(nx,ny);
                else st.insert(nx*2020+ny);//将所有的红色格子进行编码存储到set中
          }
    }
}
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>s[i][j];
        int blue=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(s[i][j]=='.') blue++;
        int win=0;
        memset(vis,false,sizeof vis);//每一次操作前初始化
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                if(s[i][j]=='#'&&vis[i][j]==false)
                {
                    st.clear();//每一次操作前初始化
                    dfs(i,j);
                    if(st.size()==blue) win=1;
                }
            }
        if(blue==n*m) cout<<"Blue"<<endl;
        else if(!win) cout<<"Draw"<<endl;
        else cout<<"Red"<<endl;
    }
    return 0;
}

D.冥古之潮 

分析:1.以 x 为起点,bfs一遍图,处理出来数组 cnt[i] 表示距离 x 为 i 的结点的数量(因为题目中dis[i]为最短距离,因此用BFS搜索)

2.

#include <bits/stdc++.h>
typedef long long ll;//记得开long long
using namespace std;
const int maxn = 1e6 + 10;
const int maxm = 5e3+10;
const int mod = 1e9 + 7;
vector<ll> g[maxn];//用邻接矩阵存图
ll dep[maxn], d[maxn], vis[maxn];
ll dp[maxm][maxm];
ll n, m, q, x;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m >> q >> x;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin>>u>>v;
        g[u].push_back(v);//用邻接矩阵存图
        g[v].push_back(u);
    }
    queue<int> qu;
    qu.push(x);
    vis[x] = 1;
    while (!qu.empty())//bfs一遍图
    {
        int u = qu.front();
        qu.pop();
        for (auto t : g[u])
        {
            if (vis[t])
                continue;
            vis[t] = 1;
            dep[t] = dep[u] + 1;
            d[dep[t]]++;
            qu.push(t);
        }
    }
    dp[0][0] = 1;
    for (int i = 1; i <= 5000; i++)
    {
        for (int k = 0; k <= 5000; k++)
        {
            dp[i][k] = dp[i - 1][k];//不选第i个点,直接转移
            if (k)//选第i个点
                dp[i][k] = dp[i][k] + dp[i - 1][k - 1] * d[i];
            dp[i][k] %= mod;
        }
    }
    while (q--)
    {
        int k;
        cin >> k;
        cout << dp[5000][k] << endl;
    }
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值