CCF CSP 202006-5 喬喬和牛牛逛超市

【題目描述】 喬喬和牛牛去逛超市了贸铜,超市里有 n 種商品聪廉,他們決定買一些商品回家。但是酥馍,第i 種商品一旦被選擇辩昆,購買的個(gè)數(shù)就必須是 Li 和 Ri 之間的整數(shù)(含端點(diǎn))。某些商品之間有依賴關(guān)系旨袒,依賴關(guān)系有兩種:
? 1. 只有第 x 種商品被購買了汁针,第 y 種商品才可以被購買。

? 2. 只有第 x 種商品被購買了砚尽,第 y 種商品的購買個(gè)數(shù)才可以恰好是 Lx 或 Rx 施无。

購買一個(gè)商品的帶來的開心程度和這個(gè)商品購買的個(gè)數(shù)有關(guān),若第 i 個(gè)商品購買了x 個(gè) x > 0 必孤,則收益為 ai * x * x + bi * x + ci 猾骡,否則為 0 。

現(xiàn)在牛牛和喬喬想知道逛超市的最大總開心程度是多少敷搪,你能幫他們選購商品并確定購買商品數(shù)量嗎兴想?

【輸入格式】
從標(biāo)準(zhǔn)輸入讀入數(shù)據(jù)。

第一行包含兩個(gè)整數(shù) n 赡勘,m 嫂便,表示商品數(shù)量和依賴關(guān)系數(shù)量。0 ≤ n ≤ 10^4,0 ≤ m ≤ 10^5闸与。

接下來 n 行顽悼,每行包含五個(gè)整數(shù) Li,Ri,ai,bi,ci ,描述一個(gè)商品几迄。1 ≤ Li ≤ Ri ≤104,?5 ≤ a ≤ 5,?104 ≤ bi,ci ≤ 104, Li + 1 ≤ Ri ? 1 蔚龙。

接下來 m 行,每行包含三個(gè)整數(shù) z, x,y 映胁,表示第 x 種商品對(duì)第 y 種商品存在第 z種關(guān)系木羹。1 ≤ x,y ≤ n,1 ≤ z ≤ 2。

【輸出格式】
輸出到標(biāo)準(zhǔn)輸出。
輸出一個(gè)整數(shù)坑填,表示最大總開心程度抛人。

image.png

【樣例1 輸出】

231

破題思路

  1. 有一組商品,選擇有依賴關(guān)系脐瑰,每個(gè)點(diǎn)有一個(gè)權(quán)值妖枚。我們要選擇任意多種使得權(quán)值最大,這個(gè)是一個(gè)最大權(quán)閉合子圖模型苍在。

  2. 所謂閉合子圖绝页,就是在一個(gè)有向圖中,我們選一組點(diǎn)集寂恬,使得這個(gè)點(diǎn)的集合续誉,里的所有出邊,都在這個(gè)點(diǎn)集內(nèi)部初肉。又稱肥水不流外人田酷鸦。
    因?yàn)橐粋€(gè)點(diǎn)集不能有出邊。我們要保證依賴關(guān)系牙咏。就是先選的要是被指的臼隔。比如選課,要先選語言課妄壶,完成了語言課的才能去選程設(shè)課躬翁。那么要從程設(shè)課向語言課指一條邊。
    那么閉合子圖的沒有出邊就能保證盯拱,不會(huì)有需要先選的沒選盒发,而選了又依賴的東西。

  3. 本來每個(gè)物品就是一個(gè)點(diǎn)狡逢,這個(gè)點(diǎn)的權(quán)值宁舰,我們可以基于二次函數(shù)求范圍內(nèi)的最大值貪心到它的權(quán)值。但是這題有2種依賴關(guān)系奢浑,所以我們可以運(yùn)用拆點(diǎn)的思想蛮艰。每個(gè)物品我們拆成2種。一種是可以買但是不能買邊界雀彼,另一種是在可以買的基礎(chǔ)上還能買邊界壤蚜。

  4. 所有買邊界的要依賴于可以買的。也就是必須先選可以買徊哑,才能選買邊界袜刷。

  5. 針對(duì)可以買,我們要計(jì)算二次函數(shù)里【L+1, R-1】的最大值莺丑。 針對(duì)買邊界就是二次函數(shù)取L還是取R的最大值著蟹。

  6. 這2類點(diǎn)要求是互斥的墩蔓,也就是說如果用了買邊界,我們不能把買當(dāng)中的第一類點(diǎn)的權(quán)值再算進(jìn)去萧豆。所以我們構(gòu)建第二類的點(diǎn)奸披,需要用它的最大值減去第一類點(diǎn)的最大值。這樣點(diǎn)集里包含第一類點(diǎn)代表買當(dāng)中涮雷,如果2個(gè)都包含阵面,代表買邊界。

  7. 余下的就是最大權(quán)閉合子圖的模板了洪鸭。所有源點(diǎn)向所有正權(quán)點(diǎn)建邊样刷。負(fù)權(quán)點(diǎn)向匯點(diǎn)建邊。內(nèi)部邊的容量都為無窮大卿嘲。隨后跑DINIC算法求最大流等價(jià)于最小割颂斜。然后用所有正權(quán)點(diǎn)的和減去最小割的值就是答案夫壁。

  8. 這道題寫完提交直接就AC還是很爽的拾枣。大家加油!

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Main m = new Main();
        System.out.println(m.solve());
    }
    // 下面這組變量是DINIC跑最大流的基礎(chǔ)變量盒让。n是點(diǎn)數(shù)梅肤,m是邊數(shù)
    int N = 20020, M = 300010, inf = (int) 1e9;
    // h e ne 3個(gè)數(shù)組 是數(shù)組模擬鄰接表的建圖方式,加邊函數(shù)參加ADD
    // w 代表 殘留網(wǎng)絡(luò)的剩余容量邑茄。 d 是對(duì)所有點(diǎn)建立分層圖姨蝴,維護(hù)層數(shù)
    // cur 是當(dāng)前層優(yōu)化的數(shù)組 S代表源點(diǎn) T代表匯點(diǎn)
    int[] h = new int[N], cur = new int[N], d = new int[N]; 
    int[] e = new int[M], ne = new int[M], w = new int[M];
    int S, T, idx = 0;
    
    int[][] goods;
    void add(int a, int b, int c) {
        e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
        e[idx] = a; w[idx] = 0; ne[idx] = h[b]; h[b] = idx++;
    }
    private long solve() {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        goods = new int[n+1][];
        S = 0; T = 2 * n + 1;
        Arrays.fill(h, -1);
        
        long tot = 0; // 存所有正權(quán)點(diǎn)的和
        for (int i = 1; i <= n; i++) {
            goods[i] = new int[]{sc.nextInt(), sc.nextInt(),sc.nextInt(),sc.nextInt(),sc.nextInt()};
            int v1 = cal(goods[i]), v2 = cal2(goods[i]) - v1;
            // i + n 是第二類點(diǎn),i是第一類點(diǎn)
            add(i + n, i, inf);
            tot += Math.max(0, v1) + Math.max(0, v2);
            if (v1 > 0) add(S, i, v1);
            else if (v1 < 0) add(i, T, -v1);

            if (v2 > 0) add(S, i+n, v2);
            else if (v2 < 0) add(i+n, T, -v2);
        }

        for (int i = 0; i < m; i++) {
            int type = sc.nextInt(), x = sc.nextInt(), y = sc.nextInt(), yy = y + n;
            if (type == 1) {
                add(y, x, inf);
            } else {
                add(yy, x, inf);
            }
        }
        
        // 正權(quán)和-最小割 為 最大閉合子圖的解
        return tot - dinic();
    }

    // dinic 模板
    private long dinic() {
        long r = 0, flow;
        while (bfs()) while ((flow = find(S, inf)) != 0) r += flow;
        return r;
    }
    // dinic find 函數(shù)模板肺缕,帶當(dāng)前層優(yōu)化
    private int find(int u, int limit) {
        if (u == T) return limit;
        int flow = 0;
        for (int i = cur[u]; i != -1 && flow < limit; i = ne[i]) {
            int j = e[i];
            cur[u] = i;
            if (d[j] == d[u] + 1 && w[i] > 0) {
                int v = find(j, Math.min(w[i], limit - flow));
                if (v == 0) d[j] = -1;
                w[i] -= v; w[i ^ 1] += v; flow += v;
            }
        }
        return flow;
    }

    // dinic bfs 建分層圖模板
    private boolean bfs() {
        Arrays.fill(d, -1);
        cur = h.clone();
        Queue<Integer> q = new LinkedList<>();
        q.offer(S); d[S] = 0;
        while (!q.isEmpty()) {
            int a = q.poll();
            for (int i = h[a]; i != -1; i = ne[i]) {
                int b = e[i];
                if (d[b] == -1 && w[i] > 0) {
                    d[b] = d[a] + 1;
                    if (b == T) return true;
                    q.offer(b);
                }
            }
        }
        return false;
    }

    // 二次函數(shù)求值
    int y(int a, int b, int c, int x) {
        return a * x * x + b * x + c;
    }
    // 第二類點(diǎn)求最大值
    private int cal2(int[] g) {
        return Math.max(y(g[2],g[3],g[4],g[0]), y(g[2],g[3],g[4],g[1]));
    }
    // 第一類點(diǎn)求最大值
    private int cal(int[] g) {
        int a = g[2], b = g[3], c = g[4], l = g[0], r = g[1];
        if (l + 1 > r - 1) return 0;
        if (a > 0) return Math.max(y(a,b,c,l+1), y(a,b,c,r-1));
        else if (a < 0) {
            double maxX = -b / 2.0 / a;
            if (maxX <= l) return y(a, b, c, l + 1);
            else if (maxX >= r) return y(a, b, c, r - 1);
            return Math.max(y(a, b, c, (int)Math.floor(maxX)), y(a, b, c, (int)Math.ceil(maxX)));
        }
        return y(a, b, c, b > 0 ? r - 1 : l + 1);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末左医,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子同木,更是在濱河造成了極大的恐慌浮梢,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彤路,死亡現(xiàn)場離奇詭異秕硝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)洲尊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門远豺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坞嘀,你說我怎么就攤上這事躯护。” “怎么了丽涩?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵榛做,是天一觀的道長。 經(jīng)常有香客問我,道長检眯,這世上最難降的妖魔是什么厘擂? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮锰瘸,結(jié)果婚禮上刽严,老公的妹妹穿的比我還像新娘。我一直安慰自己避凝,他們只是感情好舞萄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著管削,像睡著了一般倒脓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上含思,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天崎弃,我揣著相機(jī)與錄音,去河邊找鬼含潘。 笑死饲做,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遏弱。 我是一名探鬼主播盆均,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼漱逸!你這毒婦竟也來了泪姨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤饰抒,失蹤者是張志新(化名)和其女友劉穎肮砾,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體循集,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唇敞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了咒彤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疆柔。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖镶柱,靈堂內(nèi)的尸體忽然破棺而出旷档,到底是詐尸還是另有隱情,我是刑警寧澤歇拆,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布鞋屈,位于F島的核電站范咨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏厂庇。R本人自食惡果不足惜渠啊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望权旷。 院中可真熱鬧替蛉,春花似錦、人聲如沸拄氯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽译柏。三九已至镣煮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鄙麦,已是汗流浹背典唇。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黔衡,地道東北人蚓聘。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓腌乡,卻偏偏與公主長得像盟劫,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子与纽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348