1. 程式人生 > >CCF 201703-5 引水入城

CCF 201703-5 引水入城

問題描述

    MF城建立在一片高原上。由於城市唯一的水源是位於河谷地帶的湖中,人們在坡地上修築了一片網格狀的抽水水管,以將湖水抽入城市。
如下圖所示:

這裡寫圖片描述

    這片管網由 n 行 m 列節點(紅色,圖中 n = 5,m = 6),橫向管道(紫色)和縱向管道(橙色)構成。
    行和列分別用 1 到 n 的整數和 1 到 m 的整數表示。第 1 行的任何一個節點均可以抽取湖水,湖水到達第 n 行的任何一個節點即算作
引入了城市。
    除第一行和最後一行外,橫向相鄰或縱向相鄰的兩個節點之間一定有一段管道,每一段管道都有各自的最大的抽水速率,並需要根據情況選擇
抽水還是放水。對於縱向的管道(橙色),允許從上方向下方抽水或從下方向上方放水;如果從圖中的上方向下方抽水,那麼單位時間內能通過的
水量不能超過管道的最大速率;如果從下方向上方放水,因為下方海拔較高,因此可以允許有任意大的水量。對於橫向的管道(紫色),允許
從左向右或從右向左抽水,不允許放水,兩種情況下單位時間流過的水量都不能超過管道的最大速率。
    現在MF城市的水務負責人想知道,在已知每個管道單位時間容量的情況下,MF城每單位時間最多可以引入多少的湖水。

輸入格式

    由於輸入規模較大,我們採用偽隨機生成的方式生成資料。
    每組資料僅一行包含 6 個非負整數 n, m, A, B, Q, X0。其中,n 和 m 如前文所述,表示管網的大小,保證 2 ≤ n, m ≤ 5000;保證
    1 ≤ A, B, Q, X0 ≤ 109。
    A, B, Q, X0 是資料生成的引數,我們用如下的方式定義一個數列 { Xi }:
    Xi+1 = ( AXi + B) mod Q, (i ≥ 0)
    我們將數列的第 1 項到第 (n-1)m 項作為縱向管道的單位時間容量,其中 X(s-1)m+t 表示第 s 行第 t 列的節點到第 s+1 行第 t 列
管道單位時間的容量;將數列的第 (n-1)m+1 項到第 (n-1)m+(n-2)(m-1) 項(即接下來的 (n-2)(m-1) 項)作為橫向管道的單位時間容量,
其中 X(n-1)m+(s-2)(m-1)+t 表示第 s 行第 t 列的節點到第 s 行第 t+1 列管道單位時間的容量。

輸出格式

輸出一行一個整數,表示MF城每單位時間可以引入的水量。
注意計算過程中有些引數可能超過32位整型表示的最大值,請注意使用64位整型儲存相應資料。

樣例輸入

3 3 10 3 19 7

樣例輸出

38

樣例說明

使用引數得到數列 { Xi }={ 7, 16, 11, 18, 12, 9, 17, 2, 4, … },按照輸入格式可以得到每個管道的最大抽水量如下圖所示:

這裡寫圖片描述

在標準答案中,單位時間可以引水 38 單位。所有縱向管道均向下抽水即可,不需要橫向管道抽水,也不需要向上放水。

樣例輸入

2 5 595829232 749238243 603779819 532737791

樣例輸出

1029036148

樣例輸入

5 2 634932890 335818535 550589587 977780683

樣例輸出

192923706

樣例輸入

5 5 695192542 779962396 647834146 157661239

樣例輸出

1449991168

評測用例規模與約定

共有10組評測資料,每組資料的引數規模如下所示:

這裡寫圖片描述
解題思路

本題參考了網上的題解,不過最後只有60分,歡迎大家在下面給出AC程式碼。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
#define N 5010
int n, m;
int a[N][N], b[N][N];
int read() {
    int A, B, Q, XI;
    scanf("%d%d%d%d%d%d", &n, &m, &A, &B, &Q, &XI);
    //a
    for (int i = 1; i<n; i++)
        for (int j = 1; j <= m; j++) {
            XI = (1ll * A*XI + B) % Q;
            a[i][j] = XI;
        }
    //b
    for (int i = 2; i <= n - 1; i++)
        for (int j = 1; j<m; j++) {
            XI = (1ll * A*XI + B) % Q;
            b[i][j] = XI;
        }
    return 0;
}
int ed;
int ed_x[N], ed_y[N];
int ed_w[N];
int getEdge(int x, int y) { //從(x,y)出發點連邊
    ed = 0;
    if (x == 0) {    //起始或終點
        if (y == 0) { //s
            for (int i = 1; i<n; i++) {
                ed++;
                ed_x[ed] = i;
                ed_y[ed] = 1;
                ed_w[ed] = a[i][1];
            }
        }
    }
    else {  //格子節點
            //右
        ed++;
        if (y == m - 1) {//通向匯點t
            ed_x[ed] = 0; ed_y[ed] = 1; ed_w[ed] = a[x][m];
        }
        else {
            ed_x[ed] = x; ed_y[ed] = y + 1; ed_w[ed] = a[x][y + 1];
        }
        //左
        if (y>1) {
            ed++;
            ed_x[ed] = x; ed_y[ed] = y - 1; ed_w[ed] = a[x][y];
        }
        //下
        if (x<n - 1) {
            ed++;
            ed_x[ed] = x + 1; ed_y[ed] = y; ed_w[ed] = b[x + 1][y];
        }
        //上
        if (x>1) {
            ed++;
            ed_x[ed] = x - 1; ed_y[ed] = y; ed_w[ed] = b[x][y];
        }
    }
    return 0;
}
void showEd() {
    for (int i = 1; i <= ed; i++) {
        printf("(%d,%d) %d\n", ed_x[i], ed_y[i], ed_w[i]);
    }
}
bool done[N][N];
long long d[N][N];
struct NODE {
    int x, y;
    long long d;
    NODE(int x = 0, int y = 0, long long d = 0) :x(x), y(y), d(d) {}
    bool operator <(const NODE& rhs)const {
        return d>rhs.d;
    }
};
#define INF (9187201950435737471ll)
priority_queue<NODE> Q;
long long solve() {
    memset(d, 127, sizeof(d));
    d[0][0] = 0;
    memset(done, 0, sizeof(done));
    Q.push(NODE(0, 0, 0));
    while (!Q.empty()) {
        NODE nd = Q.top(); Q.pop();
        if (nd.x == 0 && nd.y == 1) return nd.d;
        if (done[nd.x][nd.y])continue;
        done[nd.x][nd.y] = true;
        d[nd.x][nd.y] = nd.d;
        getEdge(nd.x, nd.y);
        for (int i = 1; i <= ed; i++) {
            int x = ed_x[i];
            int y = ed_y[i];
            int w = ed_w[i];
            //printf("(%d,%d)->(%d,%d) %d\n",nd.x,nd.y,x,y,w);
            if (d[x][y]>d[nd.x][nd.y] + w) {
                d[x][y] = d[nd.x][nd.y] + w;
                Q.push(NODE(x, y, d[x][y]));
            }
        }
    }
    return 0;
}
int main() {
    read();
    /*for (int i=1;i<n;i++,putchar('\n'))
    for (int j=1;j<=m;j++)printf("%d ",a[i][j]);
    getEdge(0,0);
    showEd();*/
    cout << solve() << endl;
    return 0;
}