繁华模拟赛 过河

#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ll long long
#define mkp make_pair
using namespace std;

const int MaxN = 255 * 255, MaxM = MaxN * 255, inf = 1000000000;
int N, M, x[MaxN], y[MaxN], W, Hash[255][255], To[255][255][255], indx[MaxN], indy[MaxN];
bool endp[MaxN];
struct Disk {
    int r, c;
    bool operator < (const Disk &a) const {
        if (r != a.r) return r < a.r;
        return c > a.c;
    }
}    d[MaxN], disk[MaxN];

ll sqr(ll x) { return x * x; }
ll GetDist(int i, int j) {
    return sqr(x[i] - x[j]) + sqr(y[i] - y[j]);
}

struct Node {
    int d, x;
    bool operator < (const Node &a) const {
        return d > a.d;
    }
    Node() {}
    Node(int d, int x) :d(d), x(x) {}
};

bool done[MaxN];
int dist[MaxN];
priority_queue <Node> Q;

int Dijkstra() {
    while (!Q.empty()) {
        int u = Q.top().x, i = indx[u], k = indy[u];
//        printf("%d %d\n", u, dist[u]);
        Q.pop();
        if (done[u]) continue;
        done[u] = 1;
        if (endp[u]) return dist[u];
        if (indy[u] != M) {
            int v = u + 1;
            if (dist[v] > dist[u] + disk[indy[v]].c - disk[indy[u]].c) {
                dist[v] = dist[u] + disk[indy[v]].c - disk[indy[u]].c;
                Q.push(Node(dist[v], v));
            }
        }
        for (int j = 1; j <= N; j++)
            if ((j != indx[u]) && (To[i][j][k] <= M)) {
                int v = Hash[j][To[i][j][k]];
                if (dist[v] > dist[u] + disk[To[i][j][k]].c) {
                    dist[v] = dist[u] + disk[To[i][j][k]].c;
                    Q.push(Node(dist[v], v));
                }
            }
    }
    return inf;
}

void Main() {
    int dtot;
    scanf("%d%d%d", &N, &dtot, &W);
    for (int i = 1; i <= N; i++) scanf("%d%d", x + i, y + i);
    for (int i = 1; i <= dtot; i++) {
        scanf("%d%d", &d[i].r, &d[i].c);
    }
    sort(d + 1, d + dtot + 1);
    M = 0;
    for (int i = 1; i <= dtot; i++) {
        while(M && (disk[M].c > d[i].c)) M--;
        disk[++M] = d[i];
    }

    int total = 0;
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= M; j++) {
            Hash[i][j] = ++total;
            indx[total] = i;
            indy[total] = j;
        }

    Q = priority_queue <Node>();
    memset(done, 0, sizeof(done));
    memset(dist, 63, sizeof(dist));
    memset(endp, 0, sizeof(endp));
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            if (disk[j].r >= y[i]) {
                dist[Hash[i][j]] = disk[j].c;
                Q.push(Node(dist[Hash[i][j]], Hash[i][j]));
            }
            if (disk[j].r >= W - y[i]) endp[Hash[i][j]] = 1;
        }

        for (int j = 1; j <= N; j++)
            if (j != i) {
                ll dist = GetDist(i, j);
                int ind = M + 1;
                for (int k = 1; k <= M; k++) {
                    while ((ind > 1) && ((ll)(disk[k].r + disk[ind - 1].r) * (disk[k].r + disk[ind - 1].r) >= dist))
                        ind--;
                    To[i][j][k] = ind;
                }
            }
    }
    int ret = Dijkstra();
    if (ret < inf) printf("%d\n", ret);
    else printf("impossible\n");
}

int main()
{
    int T;
    freopen("river.in","r",stdin);
    freopen("river.out","w",stdout);
    scanf("%d", &T);
    while (T--) {
        Main();
    }
    return 0;
}
时间: 2024-12-16 11:25:39

繁华模拟赛 过河的相关文章

[繁华模拟赛]Evensgn 剪树枝

Evensgn 剪树枝 题目 繁华中学有一棵苹果树.苹果树有 n 个节点(也就是苹果),n − 1 条边(也就 是树枝).调皮的 Evensgn 爬到苹果树上.他发现这棵苹果树上的苹果有两种:一 种是黑苹果,一种是红苹果.Evensgn 想要剪掉 k 条树枝,将整棵树分成 k + 1 个 部分.他想要保证每个部分里面有且仅有一个黑苹果.请问他一共有多少种剪树枝 的方案? INPUT 第一行一个数字 n,表示苹果树的节点(苹果)个数. 第二行一共 n − 1 个数字 p0, p1, p2, p3,

繁华模拟赛 Evensgn的债务

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #define ll int using namespace std; const int maxn = 1000005; ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(

繁华模拟赛 ljw分雕塑

/* 用f[i][k]表示考虑到第i个雕塑,分成k组,可不可行(这是一个bool类型的数组) 转移: f[i][k]=f[j][k-1],sum[i]-sum[j]合法 */ #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const int max_n = 2010;

繁华模拟赛 找十字架

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; int n; char s[205][205],cmd; int main(){ freopen("puzzle.in","r",stdin); freopen("puzzle

繁华模拟赛 Vincent的城堡

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll mod = 1000000007; ll n,k,c[20][20]; ll ansa,ansb,ans; void get_c(){ for(int i = 1;i

繁华模拟赛 Evensgn玩序列

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 5000; int n,a[maxn],b[maxn],c[maxn],rka[maxn],rkb[maxn],rkc[maxn]; bool visa[maxn],visb[maxn],vi

繁华模拟赛 ljw搭积木

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 6005; int n,x[maxn]; int cmd,cnt,ans,max_x; int main(){ freopen("box.in","r"

繁华模拟赛 Vicent坐电梯

/*n<=5000­这样就不能用O(n)的转移了,而是要用O(1)的转移.­注意我们每次的转移都来自一个连续的区间,而且我们是求和­区间求和?­前缀和!­令sum[step][i]表示f[step][1~i]的和­还是以B下侧为例­ f[step][i]=sum[step-1][i-1]+sum[step-1][k]-sum[step-1][i] */#include <cstdio> #include <cstring> #include <cstdlib> #

繁华模拟赛 Evensgn剪树枝

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std; const int maxn = 100005; const ll mod = 1000000007; struct edge{ int t