160701總結

額,猶豫了半天,還是發出來了233
反正也沒有人看對不233

T1
題目大意:給定三場比賽的排名 (1 ~ n),問有多少對 i,j 使得存在 i 的排名比 j 高和 j 的排名比 i 高的比賽

一眼看去是個三維偏序對不對,然後直接上 cdq 就 T 了不是….

嘛,其實可以算 (a,b),(a,c),(b,c),(b,a),(c,a),(c,b),其中 (a,b) 代表在比賽 a 的排名更高,比賽 b 的排名更低的隊伍有多少對,然後除以 4 就好了…

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#define N 200005
using namespace std;

int n;
long long ans;
int a[N],b[N],c[N],t[N],T[N];

void add(int x,int c)
{
    for (;x <= n;x += x & -x) T[x] += c;
}

int query(int x)
{
    int ret = 0;
    for (;x;x ^= x & -x) ret += T[x];
    return ret;
}

void work(int *a,int *b)
{
    memset(T,0,sizeof(T));
    for (int i = 1;i <= n;i ++) t[a[i]] = b[i];
    for (int i = 1;i <= n;i ++)
        ans += i - 1 - query(t[i]),add(t[i],1);
}

int main()
{
    freopen("contest.in","r",stdin);
    freopen("contest.out","w",stdout);

    scanf("%d",&n);
    for (int i = 1;i <= n;i ++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
    work(a,b),work(b,c),work(a,c);
    work(b,a),work(c,b),work(c,a);
    cout << ans / 4 << endl;

    return 0;
}

T2

題目大意:給定並排的 n 條河流,每條河流有流速 v[i],你划船的速度爲 u,並且給定了每條河的寬度 wi 和總時間,求離開最遠點的距離

其實就是求 Δy 最大,設每段的時間爲 xi ,則 wixi 取導後的值相等,設爲 λ ,而 λ 一定 x 也一定,且成反比,所以就可以二分 λ 來判斷啦
其中要注意二分的範圍
而且要用 long double

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#define D long double
using namespace std;

int n;D u,t,sum,l,r;
D w[55],v[55];
D as[55];

bool check(D l)
{
    D ans = 0;
    for (int i = 1;i <= n;i ++)
    {
        D tmp = u * u * w[i] * w[i];
        tmp /= (l - v[i]) * (l - v[i]) - u * u;
        tmp = sqrt((tmp + w[i] * w[i]) / u / u);
        if (tmp <= w[i] / u) return false;
        ans += tmp;
        if (ans > t) return true;
    }
    return false;
}

D cal(D l)
{
    D ans = 0;
    for (int i = 1;i <= n;i ++)
    {
        D tmp = u * u * w[i] * w[i];
        tmp /= (l - v[i]) * (l - v[i]) - u * u;
        tmp = sqrt((tmp + w[i] * w[i]) / u / u);
        as[i] = tmp;
        ans += sqrt(u * u * tmp * tmp - w[i] * w[i]) + tmp * v[i];
    }
    return ans;
}

int main()
{
    freopen("river.in","r",stdin);
    freopen("river.out","w",stdout);

    cin >> n >> u >> t;
    for (int i = 1;i <= n;i ++)
        cin >> w[i] >> v[i],l = max(l,v[i]),sum += w[i];
    if (sum / u > t) {puts("-1");return 0;}
    l += u,r = 1e7;
    for (int i = 1;i <= 100;i ++)
    {
        D mid = (l+r) * .5;
        if (check(mid)) l = mid;
            else r = mid;
    }
    D y = cal(l);
    printf("%.3f\n",(double)sqrt(y*y + sum*sum));
    for (int i = 1;i <= n;i ++) printf("%.3f ",(double)as[i]);

    return 0;
}

T3

題目大意:給出一棵樹和一些幫派,幫派的控制範圍是由一些點和這些點之間的路徑組成的。每次詢問的時候給出一個點和一些幫派,求這個點到這些幫派控制範圍的距離。

假如只有一個幫派,那麼有三種情況
1)幫派爲這個點的子樹,那麼求幫派的lca就好了
2)幫派包含了這個點,那麼答案爲0
3)這個點在lca的子樹中,且未被包含,那麼如果將幫派裏的點按dfs序排序,那麼找到與它相鄰的兩個點,取個距離的最小值就可以了

現在考慮多個幫派
先對每一個幫派按上述方法求一次,現在要求幫派之間的貢獻,其實每個幫派取一個點就好了。

真·noip模擬題orz

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#define N 500005
#define INF 1000000000
using namespace std;

int n,m,q,siz,tot,x,y,w,V,ans;
int first[N],next[N*2],to[N*2];
int num[N],lca[N],d[N],p[N],g[N][20];
vector <int> v[N];

void inser(int x,int y)
{
    next[++ siz] = first[x];
    first[x] = siz;
    to[siz] = y;
}

void dfs(int x)
{
    num[x] = ++ tot;
    for (int i = first[x];i;i = next[i])
        if (to[i] ^ g[x][0])
        {
            g[to[i]][0] = x,d[to[i]] = d[x] + 1;
            for (int k = 0;g[x][k];k ++)
                g[to[i]][k + 1] = g[g[to[i]][k]][k];
            dfs(to[i]);
        }
}

int LCA(int x,int y)
{
    if (d[x] < d[y]) swap(x,y);
    for (int i = 18;~i;i --)
        if (d[g[x][i]] >= d[y]) x = g[x][i];
    if (x == y) return x;
    for (int i = 18;~i;i --)
        if (g[x][i] ^ g[y][i])
            x = g[x][i],y = g[y][i];
    return g[x][0];
}

bool cmp(const int &a,const int &b)
{
    return num[a] < num[b];
}

int main()
{
    freopen("alliances.in","r",stdin);
    freopen("alliances.out","w",stdout);

    scanf("%d",&n);
    for (int i = 1;i < n;i ++)
    {
        scanf("%d%d",&x,&y);
        inser(x,y),inser(y,x);
    }
    dfs(d[1] = 1);
    scanf("%d",&m);
    for (int i = 1;i <= m;i ++)
    {
        scanf("%d",&w);
        for (int j = 1;j <= w;j ++)
            scanf("%d",&x),v[i].push_back(x);
        sort(v[i].begin(),v[i].end(),cmp);
        lca[i] = v[i][0];
        for (int j = 1;j < w;j ++)
            lca[i] = LCA(lca[i],v[i][j]);
    }
    scanf("%d",&q);
    while (q --)
    {
        scanf("%d%d",&V,&w),ans = INF;
        for (int i = 1;i <= w;i ++)
        {
            scanf("%d",&x),p[i] = v[x][0];
            if (LCA(lca[x],V) ^ lca[x]) {ans = min(ans,d[lca[x]] + d[V] - 2 * d[LCA(lca[x],V)]);continue;}
            int l = 0,r = v[x].size();
            while (l < r - 1)
            {
                int mid = l+r >> 1;
                if (num[v[x][mid]] <= num[V]) l = mid;
                    else r = mid;
            }
            ans = min(ans,d[V] - d[LCA(V,v[x][l])]);
            if (r < v[x].size()) ans = min(ans,d[V] - d[LCA(V,v[x][r])]);
        }
        x = p[1];
        for (int i = 2;i <= w;i ++) x = LCA(x,p[i]);
        sort(p + 1,p + w + 1,cmp);
        if (LCA(x,V) ^ x) {printf("%d\n",min(ans,d[x] + d[V] - 2 * d[LCA(x,V)]));continue;}
        int l = 1,r = w + 1;
        while (l < r - 1)
        {
            int mid = l+r >> 1;
            if (num[p[mid]] <= num[V]) l = mid;
                else r = mid;
        }
        ans = min(ans,d[V] - d[LCA(V,p[l])]);
        if (r <= w) ans = min(ans,d[V] - d[LCA(V,p[r])]);
        printf("%d\n", ans);
    }

    return 0;
}

什麼時候開始貼代碼了2333

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章