10.2 校内集训 解题报告

版权声明:转载请声明出处,谢谢支持 https://blog.csdn.net/Dreamstar_DS/article/details/82929855

T1 拉力赛(lali)

1000ms 65536KB
【description】
车展结束后,游乐园决定举办一次盛大的山道拉力赛,平平和韵韵自然也要来参加大赛。
赛场上共有n个连通的计时点,n-1条赛道(构成了一棵树)。每个计时点的高度都不相同(父结点的高度必然大于子结点),相邻计时点间由赛道相连。由于马力不够,所以韵韵的遥控车只能从高处驶向低处。而且韵韵的车跑完每条赛道都需花费一定的时间。
举办方共拟举办m个赛段的比赛,每次从第u个计时点到第v个计时点,当然其中有不少比赛韵韵的遥控车是不能参加的(因为要上坡)。平平想知道他能参加多少个赛段的比赛,并且想知道他完成这些赛段的总用时。
【input】
第一行两个整数n,m。
接下来n-1行每行3个整数a、b、t。
表示韵韵的遥控车可以花t秒从第a个计时点到第b个计时点。
接下来m行每行2个整数u、v,意义如描述所示。
【output】
第一行输出一个正整数,表示能参加的赛段数。
第二行输出一个正整数,表示总用时。
【sample input】
input1:
6 2
1 2 1
2 4 1
2 5 1
5 6 1
1 3 1
2 6
4 5
【sample output】
output1:
1
2

【Data Constraint】
第一个计时点的高度是最高的;
u≠v;
对于50%的数据 n≤1000 m≤1000;
对于100%的数据 n≤10000 m≤100000;
答案小于2^64。

所以题目数据居然还是有U == V???
介绍一下此题的两种写法,一种即是最朴素的LCA,我们判断一下U是不是U 和 V的LCA即可
老师提供了另一种更快的方法,我们直接判断V是不是在U的DFS序的区间内即可(真好的方法)
所以本题是不是应该卡一卡
AC Code:

#include<bits/stdc++.h>
#define rg register
#define il inline
#define maxn 200005
#define ll long long
using namespace std;
il int read(){rg int x = 0 , w = 1;rg char ch = getchar();while (ch < '0' || ch > '9'){if (ch =='-') w = -1 ; ch = getchar();}while (ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}return x * w;}
struct edge{
    int to , next , v;	
}e[maxn << 1];
int head[maxn] , cnt , fa[maxn] , dep[maxn] , f[maxn][22];
ll val[maxn];
void add(int u , int v , int w){
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
    e[cnt].v = w;	
}
void dfs(int u , int faz , int depth){
    dep[u] = depth;
    f[u][0] = faz;
    for (rg int i = 1 ; i <= 20 ; ++i)	f[u][i] = f[f[u][i - 1]][i - 1];
    for (rg int i = head[u] ; i ; i = e[i].next){
        rg int to = e[i].to;
        if (to != faz){
            val[to] = val[u] + e[i].v;
            dfs(to , u , depth + 1);
        }
    }
}
int lca(int a , int b){
    if (dep[a] > dep[b]) swap(a , b);
    for (rg int i = 20 ; i >= 0 ; --i)
        if (dep[b] - dep[a] >= (1 << i)) b = f[b][i];
    if (a == b) return a;
    for (rg int i = 20 ; i >= 0 ; --i){
        if (f[a][i] != f[b][i])
            a = f[a][i] , b = f[b][i];
    }
    return f[a][0];
}
int main(){
    rg int n = read() , m = read() , u , v , w;
    for (rg int i = 1 ; i < n ; ++i){
        u = read() , v = read() , w = read();
        add(u , v , w);
        add(v , u , w);
    }
    dfs(1 , 0 , 1);
    rg int cnt = 0;
    ll ans = 0;
    for (rg int i = 1 ; i <= m ; ++i){
         u = read() , v = read();
         rg int lcax = lca(u , v);
         //if (dep[u] > dep[v]) continue;
         if (lcax == u){
         	++cnt;
            ans += val[u] + val[v] - (val[lcax] << 1);
         }
    }
    printf("%d\n%lld\n" , cnt , ans);
    return 0;	
}

T2 [HNOI2009]最小圈

https://www.luogu.org/problemnew/show/P3199

一道省选题,当然题解中的什么定理我真不值得,但是我会分数规划啊(然而考试中没想出来)
分数规划(这里是01分数规划),能解决 形如 a i / b i \sum {{a_i}} /\sum {{b_i}} 的问题,那么这里的ai就是边权,bi很简单,是点的个数,由题意得
a i / b i m i d \sum {{a_i}} /\sum {{b_i}} \ge mid (mid为二分的答案)
因此化简得 ( a i b i × m i d ) 0 \sum {({a_i} - {b_i} \times mid) \ge 0} ,因此按照分数规划的思路,我们就将边权设为 ( a i b i × m i d ) ({a_i} - {b_i} \times mid) ,然后用SPFA判断有无负环。有负环,说明答案还有较小的值未取到,我们就进一步二分
这道题BFS版找负环会挂掉,我们得用DFS版

AC Code:`

#include<bits/stdc++.h>
#define rg register
#define il inline
#define maxn 500005
#define eps 1e-10
#define ll long long
using namespace std;
il int read(){rg int x = 0 , w = 1;rg char ch = getchar();while (ch < '0' || ch > '9'){if (ch =='-') w = -1 ; ch = getchar();}while (ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}return x * w;}
struct edge{
    int to , next;
    double v;
}e[maxn << 1];
int head[maxn] , cnt , p , flag , tot[3005] , n , m , q[maxn] , vis0;
double save[maxn] , dis[3005];
int vis[maxn];
void add(int u , int v , double w){
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
    e[cnt].v = w;	
    save[cnt] = w;
}
bool spfa(int u){
    vis[u] = vis0;
    for (rg int i = head[u] ; i ; i = e[i].next){
        rg int to = e[i].to;
        if (dis[to] > dis[u] + e[i].v){
            dis[to] = dis[u] + e[i].v;
            if (vis[to] == vis0 || spfa(to)){
                return 1;	
            }
        }
    }
    vis[u]--;
    return 0;
}
bool check(double mid){
    memset(dis , 0 , sizeof(dis));
    ++vis0;
    for (rg int i = 1 ; i <= cnt ; ++i) e[i].v = save[i] - mid;
    for (rg int i = 1 ; i <= n ; ++i)
        if (spfa(i)) return 1;
    return 0;
}
int main(){
    n = read() , m = read();
    rg int u , v;
    double w;
    for (rg int i = 1 ; i <= m ; ++i){
        u = read() , v = read();
        scanf("%lf" , &w);
        add(u , v , w);
    }
    double l = -1000000001.0 , r = 1000000001.0 , ans = 0;
    while (r - l >= eps){
        double mid = (l + r) / 2;
        if (check(mid)) ans = mid , r = mid;
        else l = mid; 
    }
    printf("%.8lf" , ans);
    return 0;	
}

T3 可见点数(see)

题目描述

ZPS 经过长期的努力争取,终于成为了0901班的领操员,他要带领0901班参加广播操比赛。 现在0901班的队伍可以看作是一个 n*n 的点阵,每个人都站在格点上。现在作为领操员的 ZPS 站(0,0)点,他想知道如果0901班的队伍站齐了,他能看到多少个人的脸(假设每个人的 身高相同,体积相同)。

输入输出格式

输入格式:
一个正整数 n。

输出格式:
ZPS 能看到多少个人的脸(当然他是看不到自己的脸的)。

输入输出样例

暂无测试点
说明

100%的数据,n<=100000。

所以这是考场上唯一A的题?晕
其实这道题用埃氏筛(也就是不带优化的线性筛)即可,但我用了容斥(因为最近做容斥的题很多。。)
AC Code:

#include<bits/stdc++.h>
#define rg register
#define il inline
#define maxn 500005
#define ll long long
using namespace std;
il int read(){rg int x = 0 , w = 1;rg char ch = getchar();while (ch < '0' || ch > '9'){if (ch =='-') w = -1 ; ch = getchar();}while (ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}return x * w;}
ll f[maxn];
int primes[maxn] , cnt , res , a[maxn] , q[maxn];
bool vis[maxn];
void prime(int n){
    vis[1] = 1;
    for (rg int i = 2 ; i <= n ; ++i){
        if (!vis[i]) primes[++cnt] = i;
        for (rg int j = 1 ; j <= cnt && i * primes[j] <= n; ++j){
            vis[i * primes[j]] = 1;
            if (!(i % primes[j])) break;
        }
    }
}
void fenjie(int n){
    res = 0;
    rg int x = n , totn = 0;
    while(vis[x] && x != 1){
        if (!(x % primes[++totn])){
            a[++res] = primes[totn];
            x /= primes[totn];
        }
        while(!(x % primes[totn]))
            x /= primes[totn];
    }
    if (x != 1 && !vis[x]) a[++res] = x;
}
ll shai(int n){
    rg int k = 0 , len = 0;
    q[0] = -1;
    //cout << res << endl;
    for (rg int i = 1 ; i <= res ; ++i){
        k = len;
        for (rg int j = 0 ; j <= k ; ++j){
            q[++len] = q[j] * a[i] * (-1);	
        }
    }
    rg ll ans2 = 0;
    for (rg int i = 1 ; i <= len ; ++i){
        ans2 += n / q[i];
    }
    return (n - ans2) << 1;
}
int main(){
    int n = read();
    if (n == 1){
        cout << '0';
        return 0;	
    }
    prime(n);
    f[0] = f[1] = 0 , f[2] = 3 , f[3] = 5;
    if (f[n]){
        printf("%lld\n" , f[n]);
        return 0;	
    }
    rg ll ans = 5;
    for (rg int i = 4 ; i <= n ; ++i){
        rg int x = i - 1;
        if (!vis[x]){
            ans += (x - 1) << 1;
            continue;
        }else{
            fenjie(x);
            ans += shai(x);
        }
    }
    cout << ans;
    return 0;	
}

猜你喜欢

转载自blog.csdn.net/Dreamstar_DS/article/details/82929855