【牛客算法周周练1】题解A/C/E

https://ac.nowcoder.com/acm/contest/5086#question

A 前缀和

一个数移到左边所减少的量= 增加的量为
总的减少量
维护前缀和,枚举下标从k~n-1,找出最少的减少量delta即可

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+5;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        int k;scanf("%d",&k);
        int nums[maxn];
        ll sum[maxn]={0};
        unsigned ll ans=0;
        for(int i=1;i<=n;++i){
            scanf("%d",&nums[i-1]);
            ans+=i*nums[i-1];
            sum[i]=sum[i-1]+nums[i-1];
        }
        ll delta = 9223372036854775807;
        for(int i=n-1;i>=k;--i){
            ll dd = nums[i]*k-sum[i]+sum[i-k];
            delta=min(delta,dd);
        }
        printf("%lld\n",ans-delta);
    }
}

C 树上距离

求树上两个节点的距离有个性质:
图片说明
这道题我们求出B 到 C,C到 1的距离和 dis1
求出A 到 1的距离 dis2
如果 肯定抓不到
如果 肯定抓的到
如果 时且 则他们俩最终会在1相遇,抓不到,其他情况老师可以去守株待兔

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define LONGLONGMIN -922337203685477580
const int maxn = 2e5 + 10;
#define MAXN 200010
int p[MAXN], h[MAXN], ne[MAXN]; 
int num = 0;
int dep[MAXN / 2], f[MAXN / 2][21];
int MAXDEPTH;
//加边
void addEdge(int from, int to)
{
    p[++num] = to; 
    ne[num] = h[from];
    h[from] = num;

    p[++num] = from;
    ne[num] = h[to];
    h[to] = num;
}

// 预处理深度和倍增
void dfs(int u, int father)
{
    dep[u] = dep[father] + 1;
    for (int i = 1; (1 << i) <= dep[u]; ++i) {
        f[u][i] = f[f[u][i - 1]][i - 1];
    }
    for (int i = h[u]; i; i = ne[i])if (p[i] != father) {
            f[p[i]][0] = u;
            dfs(p[i], u);
        }
}
// 求LCA
int LCA(int u, int v){
    if(dep[u] > dep[v]) swap(u, v);
    int hu = dep[u], hv = dep[v];
    for(int det = hv - hu, i = 0; det; det >>= 1, i++){
        if(det & 1){
            v = f[v][i];
        }
    }
    if(u == v){
        return u;
    }
    for(int i = MAXDEPTH - 1; i >= 0; i--){
        if(f[u][i] == f[v][i]) continue;
        u = f[u][i];
        v = f[v][i];
    }
    return f[u][0];
}
void init()
{
    MAXDEPTH = 20;
    num = 0;
    memset(f, 0, sizeof(f));
    memset(h, 0, sizeof(h));
}
int main()
{
    int t;
    cin >> t;
    while (t--) {
        init();
        int n, q;
        cin >> n >> q;
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            cin >> u >> v;
            addEdge(u, v);
        }
        dep[0]=-1;
        dfs(1, 0);
        while (q--) {
            int a, b, c;
            cin >> a >> b >> c;
            if (b == c && b == 1) {
                cout << "NO\n";
                continue;
            }
            int dis1 = dep[b] + dep[c] - 2 * dep[LCA(b, c)] + dep[c];  // B -> C的距离+ C -> 1的距离dep[c]
            int dis2 = dep[a];
           // cout<<dis1<<" " <<dis2<<" "<<LCA(b, c)<<endl;
            if (dis1 < dis2) {
                cout << "NO\n";
            } else if (dis1 > dis2) {
                cout << "YES\n";
            } else {
                if (LCA(c, a) == 1)
                    cout << "NO\n";
                else
                    cout << "YES\n";
            }
        }
    }
    return 0;
}

E dfs打表预处理

dfs打表预处理出只含有4、7的数字
然后O(n)顺着往下找即可,比如l=48 找到第一个大于l的数为74 则[48,74]这个区间的数的下一个幸运数都为74。参看代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5+5;
ll a[N], k = 0;
void dfs(ll n)  //打表
{
    if(n>2e10) return;
    a[k++] = n;
    dfs(n*10+4);
    dfs(n*10+7);
}

int main()
{
    dfs(0);
    sort(a,a+k);
    ll l,r;
    scanf("%lld %lld",&l,&r);
    ll sum = 0, i = l, x = 0;
    while(i<=r)
    {
        while(a[x]<i) x++;
        sum += a[x]*(min(r,ax])-i+1);  
        i = a[x]+1;  //下一次从a[x]之后开始
    }
    printf("%lld\n",sum);
    return 0;
}
全部评论

相关推荐

从输入URL到页面加载发生了什么:总体来说分为以下几个过程:&nbsp;1.DNS解析&nbsp;2.TCP连接&nbsp;3.发送HTTP请求&nbsp;4.服务器处理请求并返回HTTP报文&nbsp;5.浏览器解析渲染页面&nbsp;6.连接结束。简述了一下各个过程的输入输出作用:以下是对从输入&nbsp;URL&nbsp;到页面加载各过程的输入、输出或作用的一句话描述:DNS&nbsp;解析:&nbsp;输入:用户在浏览器地址栏输入的域名(如&nbsp;www.example.com)。输出:对应的&nbsp;IP&nbsp;地址(如&nbsp;192.168.1.1)。作用:将易于记忆的域名转换为计算机能够识别和用于网络通信的&nbsp;IP&nbsp;地址,以便浏览器与目标服务器建立连接。TCP&nbsp;连接:&nbsp;输入:浏览器获得的服务器...
明天不下雨了:参考一下我的说法: 关键要讲出输入网址后涉及的每一个网络协议的工作原理和作用: 涉及到的网络协议: HTTP/HTTPS协议->DNS协议->TCP协议->IP协议->ARP协议 面试参考回答: 第一次访问(本地没有缓存时): 一般我们在浏览器地址栏输入的是一个域名。 浏览器会先解析 URL、解析出域名、资源路径、端口等信息、然后构造 HTTP 请求报文。浏览器新开一个网络线程发起HTTP请求(应用层) 接着进行域名解析、将域名解析为 IP 地址 浏览器会先检查本地缓存(包括浏览器 DNS 缓存、操作系统缓存等)是否已解析过该域名 如果没有、则向本地 DNS 服务器请求解析; 本地服务器查不到会向更上层的 DNS 服务器(根域名服务器->顶级域名服务器->权威域名服务器询问)递归查询 最终返回该域名对应的 IP 地址。(应用层DNS协议)DNS 协议的作用: 将域名转换为 IP 地址。 由于 HTTP 是基于 TCP 传输的、所以在发送 HTTP 请求前、需要进行三次握手、在客户端发送第一次握手的时候、( 浏览器向服务器发送一个SYN(同步)报文、其中包含客户端的初始序列号。TCP头部设置SYN标志位、并指定客户端端口 同时填上目标端口和源端口的信息。源端口是浏览器随机生成的、目标端口要看是 HTTP 还是 HTTPS、如果是 HTTP 默认目标端口是 80、如果是 HTTPS 默认是 443。(传输层) 然后到网络层:涉及到(IP协议) 会将TCP报文封装成IP数据包、添加IP头部,包含源IP地址(浏览器)和目标IP地址(服务器)。IP 协议的作用: 提供无连接的、不可靠的数据包传输服务。 然后到数据链路层、会通过 ARP 协议、获取目标的路由器的 MAC 地址、然后会加上 MAC 头、填上目标 MAC 地址和源 MAC 地址。 然后到物理层之后、直接把数据包、转发给路由器、路由器再通过下一跳、最终找到目标服务器、然后目标服务器收到客户的 SYN 报文后,会响应第二次握手。 当双方都完成三次握手后、如果是 HTTP 协议、客户端就会将 HTTP 请求就会发送给目标服务器。如果是 HTTPS 协议、客户端还要和服务端进行 TLS 四次握手之后、客户端才会将 HTTP 报文发送给目标服务器。 目标服务器收到 HTTP 请求消息后、就返回 HTTP 响应消息、浏览器会对响应消息进行解析渲染、呈现给用户
点赞 评论 收藏
分享
挣K存W养DOG:我记得好多人说这个公司就是白嫖方案的,现在有大体方案要让你给他展示实现细节了,也是无敌了
点赞 评论 收藏
分享
03-19 10:07
已编辑
广东药科大学 golang
Yki_:你倒是进一个面啊
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务