牛客小白月赛60

牛客小白月赛60_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

C小竹关禁闭
 

题目描述

妈妈成功将小竹救了出来,她觉得小竹实在是太笨了,决定关小竹一周禁闭。可是小竹哪里能忍受失去自由,他早就偷藏了一部手机用于联系你,请求你帮助他逃离。

你通过观察发现他房间内有 nnn 个可用于制成绳子的物品,第 iii 个的长度为 aia_iai​ 。当你使用第 iii 个物品制作绳子时,其右侧的 kkk 个物品(不含第iii个物品)就无法再被用于制作绳子 。最终,小竹用选择的物品制成绳子,绳子的长度是所选择物品的长度之和。

小竹想知道,他能制作的绳子长度最长为多少?

简单dp即可,dp[i] 表示 选到第i个物品为止所能凑出的最长绳子

#include<bits/stdc++.h>
using namespace std;
int n,k;
const int N=2010;
int a[N];
int dp[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        int j=max(0,i-k-1);
        dp[i]=max(dp[j]+a[i],dp[i-1]);
    }
    cout<<dp[n];
    return 0;
}

D:游戏购买!

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网

小竹成功从家里逃了出来,他决定去小胖家避一避。但是小胖要求小竹带一个刺激度大于 xxx 的游戏才能去他家。

为了防止被妈妈或她的朋友发现,小竹不会在道路上行走,而是在建筑物与建筑物之间穿行。

街道表现为一个 n×mn \times mn×m 的网格,网格上只有两种建筑: 商店和住宅。商店可以通过而住宅无法通过。

小竹每次从当前所在网格可以行走到上下左右的网格中,但不能移动到网格的边界之外和别人的家中。正式的说,如果他在坐标为 (i,j)(i,j)(i,j) 的网格里,他可以选择 (i+1,j),(i,j+1),(i−1,j),(i,j−1)(i+1,j) , (i,j+1) , (i - 1,j) , (i,j-1)(i+1,j),(i,j+1),(i−1,j),(i,j−1) 四个方向行走。

在位置 (i,j)(i,j)(i,j) 上的商店有一个刺激度为 wi,jw_{i,j}wi,j​ 的游戏,小竹可以购买他所经过的商店中的游戏并带走。若 wi,jw_{i,j}wi,j​ 为 −1-1−1 则代表这个位置是个住宅,无法通过。

注意:小胖家以及小竹家均可以被通过。

假设相邻的建筑物的距离均为 111,小竹想知道带一个刺激度高于 xxx 的游戏去小胖家需要的最短距离是多少?如果这是不可能实现的,请输出 −1-1−1。 

解法:从起点终点各BFS一次,然后枚举每个大于X的中转点即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2010;
int n,m,x;
int sx,sy,ex,ey;
ll g[N][N];
int dist[N][N];
int dist1[N][N];
void bfs1()
{
    int dx[]={1,0,-1,0};
    int dy[]={0,-1,0,1};
    queue<PII> q;
    memset(dist1,-1,sizeof dist);
    dist1[ex][ey]=0;
    q.push({ex,ey});
    while(!q.empty())
    {
        PII p=q.front();
        q.pop();
        int a=p.first,b=p.second;
        for(int i=0;i<4;i++)
        {
            int sa=a+dx[i],sb=b+dy[i];
            if(sa<1||sa>n||sb<1||sb>m)continue;
            if(g[sa][sb]==-1||dist1[sa][sb]!=-1)continue;
            dist1[sa][sb]=dist1[a][b]+1;
            q.push({sa,sb});
        }
    }
}
int bfs()
{
    int dx[]={1,0,-1,0};
    int dy[]={0,-1,0,1};
    queue<PII> q;
    memset(dist,-1,sizeof dist);
    q.push({sx,sy});
    dist[sx][sy]=0;
    while(!q.empty())
    {
        PII p=q.front();
        q.pop();
        int a=p.first,b=p.second;
        for(int i=0;i<4;i++)
        {
            int sa=a+dx[i],sb=b+dy[i];
            if(sa<1||sa>n||sb<1||sb>m)continue;
            if(g[sa][sb]==-1||dist[sa][sb]!=-1)continue;
            dist[sa][sb]=dist[a][b]+1;
            q.push({sa,sb});
        }
    }
    if(dist1[sx][sy]==-1)return -1;
    int ans=0x3f3f3f3f;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(g[i][j]>x&&dist[i][j]!=-1&&dist1[i][j]!=-1)
            {
                ans=min(ans,dist[i][j]+dist1[i][j]);
            }
        }
    }
    if(ans==0x3f3f3f3f)return -1;
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m>>x;
    cin>>sx>>sy>>ex>>ey;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)cin>>g[i][j];
    bfs1();
    cout<<bfs();
    return 0;
}

E 寻找小竹!

妈妈发现小竹逃走了,非常的气愤,她决定出去寻找小竹!和小竹不同的是,妈妈是道路上行走。

妈妈和小竹所在的城市有 nnn 个路口,n−1n-1n−1 条道路,并且保证任意两个路口互相联通。每个路口根据妈妈审美的不同都有一个优雅值,而如果两个相邻的路口的优雅值存在至少两个共同的质因子ppp和qqq(p≠qp\neq qp​=q)则这两个相邻的路口就是共同优雅的。

妈妈将共同优雅联通块定义为:在城市中选取若干个路口,若这些路口们两两互相联通,且每两个相邻的路口都是共同优雅的,则该联通块称为共同优雅联通块。

注意:单独的一个路口也符合共同优雅联通块的定义。

妈妈想知道,整个城市的最大优雅联通块包含多少个路口。

解法:首先筛出所有合数,然后将每个质数的倍数也筛出来,因为题意为两个数必须含有两个不同的质因数,然后直接树形DP即可,在dfs的时候顺便更新一下答案

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=N*2;
int n;
vector<int> primes;
bool st[(int)5e6+10];
struct node{
    int to,nxt;
}edge[M];
int cnt;
int head[N];
int w[N];
int f[N];
int ans;
void add(int from,int to)
{
    edge[cnt].to=to;
    edge[cnt].nxt=head[from];
    head[from]=cnt++;
}
void get_prime(int k)
{
    for(int i=2;i<=k;i++)
    {
        if(!st[i])primes.push_back(i);
        for(int j=0;primes[j]<=k/i;j++)
        {
            st[i*primes[j]]=true;
            if(i%primes[j]==0)break;
        }
    }
}
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
void dfs(int u,int fa)
{
    f[u]=1;
    for(int i=head[u];~i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==fa)continue;
        dfs(v,u);
        if(st[gcd(w[u],w[v])])f[u]+=f[v];
    }
    ans=max(ans,f[u]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    memset(head,-1,sizeof head);
    int m=5e6+1;
    get_prime(m);
    for(int i=0;i<(int)primes.size();i++)
    {
        for(int j=primes[i];j<=m/primes[i];j*=primes[i])st[j]=false;
    }
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=0;i<n-1;i++)
    {
        int x,y;
        cin>>x>>y;
        add(x,y),add(y,x);
    }
    dfs(1,-1);
    cout<<ans;
    return 0;
}

代码更清晰一点点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值