码迷,mamicode.com
首页 > Windows程序 > 详细

【BZOJ 4070】 [Apio2015]雅加达的摩天楼

时间:2015-05-16 12:05:34      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:bzoj   oi   分块   最短路   

4070: [Apio2015]雅加达的摩天楼

Time limit: 1000 ms

Memory limit: 262144 KB

Description

The city of Jakarta has N skyscrapers located on a line, conveniently numbered 0 through N-1 from left to right. There are no other skyscrapers in Jakarta.

Jakarta is inhabited by M mystical creatures called “doge”s. The doges are conveniently numbered 0 through M-1. Doge i initially resides in skyscraper Bi. Doge i has a mystical power, represented with a positive integer Pi. This mystical power enables doges to jump between skyscrapers. In a single jump, a doge with superpower p that is currently in skyscraper b can move to either skyscraper b+p (if 0 ≤ b+p < N) or skyscraper b-p (if 0 ≤ b-p < N).

Doge 0 is the most awesome doge, and it is the leader of all the doges. It has an urgent news for doge 1, and wants the news to reach doge 1 as quickly as possible. Any doge that has received the news can do any of the following actions:

Make a jump to move to some other skyscraper.
Pass the news to another doge in the same skyscraper.
Please help the doges by calculating the minimum number of total jumps required by all doges to pass the news to doge 1, or if it is impossible to do so.

Input Format

The first line contains two integers N and M. Each of the next M lines contains two integers Bi and Pi.

Output Format

A single line containing the minimum number of total jumps, or -1 if it is impossible.

Sample Input

5 3
0 2
1 1
4 1
Sample Output

5
Explanation

Here is one of the possible scenarios to pass the news using 5 jumps:

Doge 0 jumps to skyscraper 2 and then to skyscraper 4 (2 jumps).
Doge 0 passes the news to doge 2.
Doge 2 jumps to skyscraper 3, and then to skyscraper 2, and then to skyscraper 1 (3 jumps).
Doge 2 passes the news to doge 1.
Subtasks

For each subtask,

0 ≤ Bi < N
Subtask 1 (10 points)

1 ≤ N ≤ 10
1 ≤ Pi ≤ 10
2 ≤ M ≤ 3
Subtask 2 (12 points)

1 ≤ N ≤ 100
1 ≤ Pi ≤ 100
2 ≤ M ≤ 2,000
Subtask 3 (14 points)

1 ≤ N ≤ 2,000
1 ≤ Pi ≤ 2,000
2 ≤ M ≤ 2,000
Subtask 4 (21 points)

1 ≤ N ≤ 2,000
1 ≤ Pi ≤ 2,000
2 ≤ M ≤ 30,000
Subtask 5 (43 points)

1 ≤ N ≤ 30,000
1 ≤ Pi ≤ 30,000
2 ≤ M ≤ 30,000

分块+最短路。

这道题如果直接跑最短路,最坏可能会产生n2条边。

考虑分块:
Pi>n
可以直接暴力来做,因为最多只会有nn条边

Pin
从每个点来看,最多只有n种走法,所以一共只有nn条边。

我们可以在后面添加一些辅助点来实现预处理:
枚举这n个长度,在后面分别建出n个辅助点,连向前面对应的位置,同时连向可以来自和到达的辅助点。

对于读入直接连向他对应的辅助点即可。
(详见代码)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#define M 30005
#define pb push_back
#define LL long long
using namespace std;
queue<int> q;
int B,tot=0,cnt,s,t,h[M*110],m,n,inq[M*110];
int d[M*110],pos[105][M];
struct data
{
    int b,p;
}a[M];
struct edge
{
    int y,ne,v;
}e[M*500];
void Addedge(int x,int y,int v)
{
    e[++tot].y=y;
    e[tot].v=v;
    e[tot].ne=h[x];
    h[x]=tot;
}
void SPFA()
{
    for (int i=0;i<=cnt;i++)
        d[i]=1e9,inq[i]=0;
    q.push(a[0].b);
    d[a[0].b]=0,inq[a[0].b]=1;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        inq[x]=0;
        for (int i=h[x];i;i=e[i].ne)
        {
            int y=e[i].y;
            if (d[y]>d[x]+e[i].v)
            {
                d[y]=d[x]+e[i].v;
                if (!inq[y]) q.push(y),inq[y]=1;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<m;i++)
        scanf("%d%d",&a[i].b,&a[i].p);
    cnt=n-1;
    B=min((int)sqrt(n),100);
    for (int i=1;i<=B;i++)
        for (int j=0;j<i;j++)
            for (int k=j;k<n;k+=i)
            {
                pos[i][k]=++cnt;
                Addedge(cnt,k,0);
                if (k>=i)
                {
                    Addedge(cnt,cnt-1,1);
                    Addedge(cnt-1,cnt,1);
                }
            }
    for (int i=0;i<m;i++)
    {
        if (a[i].p<=B)
            Addedge(a[i].b,pos[a[i].p][a[i].b],0);
        else
        {
            for (int j=1;;j++)
                if (j*a[i].p+a[i].b>=n) break;
                else Addedge(a[i].b,j*a[i].p+a[i].b,j);
            for (int j=1;;j++)
                if (a[i].b-j*a[i].p<0) break;
                else Addedge(a[i].b,a[i].b-j*a[i].p,j);
        }
    }
    SPFA();
    if (d[a[1].b]==1e9)
        cout<<-1<<endl;
    else cout<<d[a[1].b]<<endl;
    return 0;
}

技术分享

【BZOJ 4070】 [Apio2015]雅加达的摩天楼

标签:bzoj   oi   分块   最短路   

原文地址:http://blog.csdn.net/regina8023/article/details/45766241

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!