沈阳集训day4

问题 A: 借书

题目描述

Dilhao一共有n本教科书,每本教科书都有一个难度值,他每次出题的时候都会从其中挑两本教科书作为借鉴,如果这两本书的难度相差越大,Dilhao出的题就会越复杂,也就是说, 一道题的复杂程度等于两本书难度差的绝对值。
这次轮到ldxxx出题啦,他想要管Dilhao借m本书作为参考去出题,Dilhao想知道,如果ldxxx在Dilhao给出的 m本书里挑选难度相差最小的两本书出题,那么ldxxx出的题 复杂程度最大是多少?

输入

 第一行是n和m。
 接下来的n行,每行一个整数ai表示第i本书的难度。

输出

 一个整数为ldxxx出的题复杂程度的最大值。

样例输入

6 3 
5
7
1
17
13
10

样例输出

7

提示

 


【样例解释】


Dilhao给了ldxxx难度为1,10,17的三本书,ldxxx挑选难度为10和17的两本书,出题复杂度为7;

如果Dilhao给出其他任何三本书,其中的两本书难度差的最小值都小于7,所以ldxxx出题的最大复杂程度为7。

【数据说明】 

对于 30%的数据: 2<=n<=20; 

对于 60%的数据: 2<=n<=1000; 

对于 100%的数据: 2<=n<=100000, 2<=m<=n, 0<=ai<=1000000000。
题解:二分
#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 1e5+5;
int a[maxn], n, m;
 
bool check(int k){
    int now = a[1], cnt = 1, pos1 = 1;
    while(cnt < m){
        int nxt = now+k;
        int pos = lower_bound(a+pos1, a+1+n+1, nxt) - a;
        if(pos == n+1)return 0;
        cnt++;
        now = a[pos];
        pos1 = pos;
    }
    return 1;
}
 
 
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
    sort(a+1, a+1+n);
    a[n+1] = 2*a[n];
    int lf = 0, rg = a[n], ans;
    while(lf <= rg){
        int mid = (lf + rg) >> 1;
        if(check(mid))ans = mid, lf = mid + 1;
        else rg = mid - 1;
    }
    printf("%d\n", ans);
    return 0;
}
View Code

 

问题 B: 追捕

题目描述

Duan2baka:“jmsyzsfq天下第一蠢!”
jmsyzsfq:“你说什么?!”
 
 
于是Duan2baka开始了逃亡的旅程,而jmsyzsfq也开始追捕Duan2baka。 他们来到了一个有n个节点的 有向图,迅速逃跑的Duan2baka会首先降落在有向图的某个节点T上,因为怕发出声音,他会永远静止不动。而随后跟来的jmsyzsfq会降落在图上 随机一个节点S上(可以与T相同),并可以沿着图中的有向边随意走动。因为jmsyzsfq有着敏锐的嗅觉而且绝顶聪明,他一定会沿着正确的方向寻找Duan2baka。你可以认为,如果图中存在一条合法的从S到T的路径,那么jmsyzsfq一定会抓到Duan2baka——因此jmsyzsfq能否追捕到Duan2baka在他刚刚降落在图上的时候就已经确定了。现在请你帮帮jmsyzsfq,在他降落前告诉他有多大的概率能够追捕到Duan2baka,并告诉他想要追到Duan2baka他可以降落在哪些节点上。

输入

输入第一行包含三个整数n,m,opt,表示图中有n个节点,m条有向边;opt为0或1,含义见输出格式所述。
    输入第2至m+1行每行两个整数u,v描述了图中一条从u到v的有向边。
输入第m+2行一个整数T表示Duan2baka降落的位置。

输出

  如果输入的opt为0,只需要输出jmsyzsfq能够追捕到Duan2baka的概率。
  如果输入的opt为1,输出两行,第一行输出jmsyzsfq能够追捕到Duan2baka的概率;第二行按从小到大输出想要追到Duan2baka他可以降落的节点编号,编号间用空格隔开。
  对于jmsyzsfq能够追捕到Duan2baka的概率,是一个 既约分数,形如“a/b”(a,b为整数),使gcd(a,b)=1,如果a=b,输出1/1。

样例输入

【样例1输入】
9 10 1
1 2
2 1
2 4
6 1
9 6
6 5
5 3
3 7
3 1
1 8
1
【样例2输入】
5 7 1
1 2
1 3
1 5
2 4
4 1
4 5
5 3
1

样例输出

【样例1输出】
 2/3
 1 2 3 5 6 9 
【样例1解释】
 图中共9个节点,能够到达节点S=1的节点共6个:{1,2,3,5,6,9}。所以能够追捕到Duan2baka的概率为6/9=2/3

【样例2输出】
 3/5
 1 2 4 

提示

 

  opt=0和opt=1的数据各50%。

对于opt=0和opt=1的情况,有着完全相同的子任务:

对于10%的数据,n,m≤100。

对于另外30%的数据,n,m≤100,000。

对于另外10%的数据,保证图是一个完全图,即对于任意两个点u和v,必然有两条有向边u→v和v→u。

对于另外20%的数据,保证图是一个有向无环图,即对于任意一个点x,不存在图上一条路径从x经过其它点后回到x。

对于另外20%的数据,保证如果图上存在一条边u→v,一定存在一条边v→u。

对于100%的数据,n,m≤1,000,000,保证数据合法且不存在重边、自环。
题解:简单bfs
#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 1e6+5;
int n, m, opt, st, cnt = 1, tot, h[maxn];
bool vis[maxn];
int gcd(int a, int b){
    return b ? gcd(b, a%b) : a;
}
struct edge{int v,nxt;}G[maxn];
void add(int u, int v){
    G[++tot].v = v; G[tot].nxt = h[u]; h[u] = tot;
}
void bfs(){
    queue <int> Q;
 
    Q.push(st);
    vis[st] = 1;
    while(!Q.empty()){
        int u = Q.front(); Q.pop();
 
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(!vis[v]){
                Q.push(v);
                vis[v] = 1;
                cnt++;
            }
        }
    }
 
}
int main()
{
    scanf("%d%d%d", &n, &m, &opt);
    for(int i = 1; i <= m; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        add(v, u);
    }
    scanf("%d", &st);
    bfs();
    int d = gcd(cnt, n);
    int p = cnt/d, q = n/d;
    printf("%d/%d\n",p,q);
    if(opt)for(int i = 1; i <= n; i++)
       if(vis[i])printf("%d ",i);
}
View Code

 

问题 C: 空间活动

题目描述

   贝茜和佩奇正在玩一款游戏,在游戏开始会生成一个有n个点m条单向边的地图,经过每条边需要花费价格为Hi的费用(Hi<=1000)。但是如果两个点可以互相到达,那么这两个点之间需要花费的价格就变为0。总共有k关,每一关会给你两个点a,b(0< a,b <=n),让你求从a走到b的最小花费。

输入

   第一行三个数n,m,k;
   接下来m行每行三个数,x,y,Hi表示存在一条(x,y)的单向边,边权为Hi;
   接下来k行每行两个数a,b。

输出

 k行,每行一个数表示从a走到b的最小花费(如果不能从a走到b,那么输出“No”)。

样例输入

4 5 5
1 2 5
2 1 10
3 4 8
4 3 7
2 3 6
1 2
1 3
1 4
4 3
4 1

样例输出

0
6
6
0
No

提示

 

   对于30%的数据n<=20,k<=1;

   对于另外30%的数据 n<=100,m=n-1,k<=50;

   对于100%的数据 n<=1000,m<=2500,k<=100;
题解:tarjan裸题
#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 3000+5;
#define inf 1000000008
int n, m, st, ed, k, tot, h[maxn], hh[maxn], tot1, dis[maxn], ans[maxn*3];
bool vis[maxn], run[maxn], inq[maxn], ins[maxn];
struct edge{int v, nxt, w;}G[maxn], g[maxn];
void add(int u, int v, int w){
    G[++tot].v = v; G[tot].nxt = h[u]; h[u] = tot; G[tot].w = w;
}
void add1(int u, int v, int w){
    g[++tot1].v = v; g[tot1].nxt = hh[u]; hh[u] = tot1; g[tot1].w = w;
}
bool spfa(){
    queue <int> Q;
    memset(dis, 127, sizeof(dis));
    memset(inq, 0, sizeof(inq));
    Q.push(st);
    inq[st] = 1;
    dis[st] = 0;
    while(!Q.empty()){
        int u = Q.front(); Q.pop();inq[u] = 0;
 
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(dis[v] > dis[u] + G[i].w){
                dis[v] = dis[u] + G[i].w;
                if(!inq[v])
                    Q.push(v),inq[v] = 1;
            }
        }
    }
    return dis[ed] < inf;
}
int dfn[maxn], low[maxn], place[maxn], scc, idx;
stack <int> t;
void tarjan(int u){
    dfn[u] = low[u] = ++idx;
    ins[u] = 1; t.push(u);
 
    for(int i = hh[u]; i; i = g[i].nxt){
        int v = g[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(ins[v]) low[u] = min(low[u], dfn[v]);
    }
 
    if(low[u] == dfn[u]){
        scc++;
        while(1){
            int tt = t.top(); t.pop();
            place[tt] = scc; ins[tt] = 0;
            if(tt == u)break;
        }
    }
}
 
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= m; i++){
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add1(u, v, w);
    }
    for(int i = 1; i <= n; i++)
        if(!dfn[i])tarjan(i);
    for(int i = 1; i <= n; i++)
    for(int j = hh[i]; j; j = g[j].nxt){
        int v = g[j].v;
        if(place[v] != place[i])
            add(place[i], place[v], g[j].w);
    }
    for(int i = 1; i <= k; i++){
        scanf("%d%d", &st, &ed);
        st = place[st], ed = place[ed];
        if(spfa())printf("%d\n", dis[ed]);
        else printf("No\n");
    }
 
}
View Code

 

今天本来是欢乐ak赛,但空间开小了,数据范围啊

转载于:https://www.cnblogs.com/EdSheeran/p/9275360.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值