程序員進(jìn)階之算法練習(xí)(九十八)

題目1

題目鏈接
題目大意:
在一個(gè)國(guó)際象棋的棋盤(pán)上绊含,有一個(gè)棋子,它的移動(dòng)規(guī)則類(lèi)似馬炊汹,能夠朝著橫or豎方向移動(dòng)距離a躬充,然后朝豎or橫(和之前不同)移動(dòng)距離b;
比如說(shuō)馬的移動(dòng)規(guī)則就是a=1讨便,b=2充甚;

現(xiàn)在棋盤(pán)上還有另外兩個(gè)棋子K和Q,問(wèn)棋盤(pán)上有多少個(gè)特殊位置霸褒,在該位置上面可以移動(dòng)棋子K所在位置伴找,也可以移動(dòng)到棋子Q所在位置。

如下废菱,該圖上面的馬技矮,可以移動(dòng)到另外兩個(gè)棋子的位置。


輸入:
第一行殊轴,整數(shù)?? 表示t個(gè)樣例 ?? (1≤??≤1000)
每個(gè)樣例3行
第1行整數(shù) ?? and ?? (1≤??,??≤1e8)
第2行整數(shù) ???? and ???? (0≤????,????≤1e8 )
第3行整數(shù) ???? and ???? (0≤????,????≤1e8 )

輸出:
每個(gè)樣例一行衰倦,輸出滿(mǎn)足要求的位置數(shù)量。

Examples
input
4
2 1
0 0
3 3
1 1
3 1
1 3
4 4
0 0
8 0
4 2
1 4
3 4

output
2
1
2
0

題目解析:
能夠攻擊到k的位置梳凛,應(yīng)該有左右上下8個(gè)角落耿币;
同理,能夠攻擊到q的位置韧拒,也同樣有8個(gè)角落淹接;
接下來(lái)枚舉前面的位置,看是否有位置與后面的角落重合叛溢,即可塑悼。

tips:
1、為了方便枚舉楷掉,可以把4個(gè)方向用dir[4][2]的數(shù)組來(lái)枚舉厢蒜;
2、a和b不相同的時(shí)候,要考慮a和b互換的情況斑鸦;

typedef long long lld;
 
class Solution {
    static const int N = 201010;
    int dir[4][2] = {1,1,  -1,1,  1,-1,   -1,-1};
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int val[2], x1, y1, x2, y2;
            cin >> val[0] >> val[1];
            cin >> x1 >> y1;
            cin >> x2 >> y2;
            int ans = 0;
            for (int i = 0; i < 8; ++i) {
                int a = val[i % 2];
                int b = val[(i + 1) % 2];
                if (a == b && i % 2) continue;;
                int idx1 = dir[i/2][0] * a + x1;
                int idy1 = dir[i/2][1] * b + y1;
                for (int j = 0; j < 8; ++j) {
                    int a2 = val[j % 2];
                    int b2 = val[(j + 1) % 2];
                    if (a2 == b2 && j % 2) continue;;
                    if ((idx1 + dir[j/2][0] * a2 == x2) && (idy1 + dir[j/2][1] * b2 == y2)) {
                        ++ans;
                        break;
                    }
                }
            }
            cout << ans << endl;
        }
    }
}
ac;

題目2

題目鏈接
題目大意:
有n個(gè)元素的整數(shù)數(shù)組a愕贡,現(xiàn)在進(jìn)行以下操作:
1、選擇某個(gè)元素a[i]巷屿,移除當(dāng)前元素a[i]固以,獲得初始分?jǐn)?shù)score=a[i];
2嘱巾、尋找某個(gè)元素a[j]憨琳,并且滿(mǎn)足score>=a[j],可以移除元素a[j]旬昭,同時(shí)使得分?jǐn)?shù)score增加a[j]篙螟;
3、不斷重復(fù)操作2问拘,直到無(wú)法執(zhí)行遍略;

現(xiàn)在想知道,每個(gè)元素被作為初始元素時(shí)场梆,最多能夠移除的元素?cái)?shù)量墅冷;

輸入:
第一行纯路,整數(shù)?? 表示t個(gè)樣例 ?? (1≤??≤5000)
每個(gè)樣例2行
第1行整數(shù) ?? (1≤??≤1e5 )
第2行n個(gè)整數(shù) ??1,??2,…,???? (1≤????≤1e9)

輸出:
每個(gè)樣例一行或油,每行n個(gè)整數(shù),第i個(gè)數(shù)字驰唬,表示當(dāng)?shù)趇個(gè)元素作為初始元素時(shí)顶岸,能夠移除的最多元素?cái)?shù)量。(也就是操作2的最多執(zhí)行次數(shù))

Examples
input
4
5
20 5 1 4 2
3
1434 7 1442
1
1
5
999999999 999999999 999999999 1000000000 1000000000

output
4 3 0 3 1
1 0 2
0
4 4 4 4 4

題目解析:
將整數(shù)數(shù)組進(jìn)行從大到小排序叫编,接著下來(lái)再考慮如何決策辖佣;
由于題目的規(guī)則很像“大魚(yú)吃小魚(yú)”,可以從數(shù)字較小者開(kāi)始搓逾,也就是從右到左:
1卷谈、最小的元素,除非和倒數(shù)第二個(gè)相同霞篡,否則無(wú)法吃下任何數(shù)字世蔗;
2、從倒數(shù)第二個(gè)數(shù)字開(kāi)始朗兵,每次可以直接累加右邊所有的數(shù)字污淋,然后如果數(shù)字和大于等于左邊的數(shù)字,就可以一直累加余掖,然后左移一位寸爆,直到無(wú)法移動(dòng);
此時(shí),該段區(qū)間內(nèi)的所有數(shù)字赁豆,最終的數(shù)字和都是一樣的仅醇;
3、重復(fù)上面的過(guò)程魔种,直到將整個(gè)數(shù)組分為若干段着憨;
比如說(shuō)[20, 5,4,2,1]就可以分為[20],[5,4], [2], [1],劃分規(guī)則就是每次從右到左累加和务嫡,小于左邊一個(gè)數(shù)字甲抖。

類(lèi)似的思考過(guò)程,假設(shè)我們排序之后是從左到右去思考心铃,還是以[20, 5,4,2,1]為例子准谚。
當(dāng)處理數(shù)字20時(shí),按照規(guī)則去扣,右邊所有數(shù)字都能吃掉柱衔,ans[0]=4;
當(dāng)處理數(shù)字5時(shí)愉棱,如果5左邊所有數(shù)字累加和大于20唆铐,那么就可以吃掉20,此時(shí)結(jié)果ans[1]=ans[0]; 但是5左邊累加數(shù)字和奔滑,結(jié)果是12艾岂,那么此時(shí)結(jié)果就是3;
因?yàn)閿?shù)組比較長(zhǎng)朋其,右邊和可以先計(jì)算整個(gè)數(shù)組和sum王浴,然后不斷累積減去當(dāng)前數(shù)字。

typedef long long lld;
 
class Solution {
    static const int N = 101010;
    pair<int, int> a[N];
    int ans[N];
    static bool cmp(pair<int, int> x, pair<int, int> y) {
        return x.first > y.first;
    }
    
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            lld sum = 0;
            for (int i = 0; i < n; ++i) {
                cin >> a[i].first;
                a[i].second = i;
                sum += a[i].first;
            }
            sort(a, a + n, cmp);
            for (int i = 0; i < n; ++i) {
                sum -= a[i].first;
                if (i == 0) {
                    ans[a[i].second] = n - i - 1;
                }
                else {
                    if (sum + a[i].first >= a[i - 1].first) {
                        ans[a[i].second] = ans[a[i - 1].second];
                    }
                    else {
                        ans[a[i].second] = n - i - 1;
                    }
                }
            }
            for (int i = 0; i < n; ++i) cout << ans[i] << " ";
            cout << endl;
        }
    }
}
ac;

題目3

題目鏈接
題目大意:
有n個(gè)整數(shù)的數(shù)組a梅猿,現(xiàn)在可以進(jìn)行下面的操作:
選擇數(shù)組中任意兩個(gè)元素氓辣,將兩個(gè)元素差值的絕對(duì)值,插入到數(shù)組中的最后面袱蚓;

現(xiàn)在可以進(jìn)行上面的操作k次钞啸,要求讓數(shù)組中的最小值在操作之后,盡可能的欣恕体斩;

輸入:
第一行,整數(shù)?? 表示t個(gè)樣例 ?? (1≤??≤1000)
每個(gè)樣例2行
第1行整數(shù)?? and ?? (2≤??≤2?1e3 , 1≤??≤1e9 )
第2行n個(gè)整數(shù) ??1,??2,…,???? (1≤????≤1e18)

輸出:
每個(gè)樣例一行响蓉,輸出操作后的最小值硕勿。

Examples
input
4
5 2
3 9 7 15 1
4 3
7 4 15 12
6 2
42 47 50 54 62 79
2 1
500000000000000000 1000000000000000000

output
1
0
3
500000000000000000

題目解析:
數(shù)組a都是大于1的值,那么最終的結(jié)果必然是大于等于0枫甲;
當(dāng)n=2的時(shí)候源武,如果a1=a2扼褪,那么結(jié)果就是0;
如果a1!=a2粱栖,那么|a1-a2|必然會(huì)產(chǎn)生一個(gè)新的數(shù)字话浇,以[4, 2]為例:
4 2
4 2 2
4 2 2 0

但是,當(dāng)a1和a2差距較大時(shí)闹究,我們有:
10 2
10 2 8
10 2 8 2
10 2 8 2 0

也就是當(dāng)操作次數(shù)沒(méi)有限制時(shí)彤钟,我們必然能夠產(chǎn)生0猩系,比如說(shuō):
c=b-a;
d=b-c=(b-(b-a))=a;
這樣數(shù)組[a, b, c, d],只需要選擇a-d=a-a=0休蟹;
只要k>=3幕侠,必然可以得到0油挥。

當(dāng)k==1時(shí)顾患,直接枚舉兩兩想減的情況,得到結(jié)果用踩;
當(dāng)k==2時(shí)渠退,我們枚舉數(shù)組兩兩想減,得到新的數(shù)字脐彩,假設(shè)是數(shù)組b碎乃;
這樣我們就有[a1, a2, a3... an] 和 [b1, b2, b3...bn]兩個(gè)數(shù)組;
這樣只需要再枚舉數(shù)組a和數(shù)組b相減惠奸,得到數(shù)組c梅誓;
最小值就是數(shù)組a、b晨川、c中的最小值证九。

這樣的復(fù)雜度删豺,首先是數(shù)組b的生成共虑,O(N^2),最多會(huì)生成1e6個(gè)數(shù)字呀页;
最后再枚舉生成c的時(shí)候妈拌,復(fù)雜度就達(dá)到了O(N^3),最終復(fù)雜度超標(biāo)蓬蝶。

重新審視問(wèn)題分析過(guò)程尘分,當(dāng)k==1時(shí),其實(shí)不需要所有數(shù)字兩兩相減丸氛,舉一個(gè)例子:
當(dāng)數(shù)組為[9,7,5,1]培愁,當(dāng)枚舉9與其他數(shù)字的差值時(shí),只需要考慮[9,7]的情況缓窜,也就是整個(gè)數(shù)組其實(shí)只需要考慮3個(gè)情況[9, 7] 定续、[7,5]谍咆、[5,1];
這里的前提私股,是數(shù)組是有序的摹察。可以對(duì)數(shù)組進(jìn)行排序倡鲸,復(fù)雜度是O(NlogN)供嚎,接下來(lái)枚舉復(fù)雜度就是O(N);
但是峭状,當(dāng)k==2時(shí)克滴,是否可以繼續(xù)只考慮相鄰數(shù)字呢?
是不可以的优床,因?yàn)橄噜彅?shù)字想減偿曙,生成的只是當(dāng)前最小,不意味著再一次操作的更小羔巢,比如說(shuō)[9,7,5,4]望忆,第一次無(wú)法生成9-5=4,那么第二次操作就無(wú)法歸零竿秆。
所以首次操作启摄,需要生成N^2個(gè)數(shù)字的數(shù)字b;
在第二次操作的時(shí)候幽钢,我們會(huì)從數(shù)組a選擇1個(gè)數(shù)字歉备,再?gòu)臄?shù)組b選擇1個(gè)數(shù)字,此時(shí)可以參考k=1的時(shí)候的做法匪燕,將數(shù)組b排序蕾羊,對(duì)于每個(gè)數(shù)字a[i],我們只需要考慮數(shù)組b中離a[i]數(shù)字最接近的數(shù)字帽驯。
此時(shí)可以用二分法龟再,在數(shù)組b中尋找。但是我們有更簡(jiǎn)單的做法:
將數(shù)組a和數(shù)組b一起排序尼变,然后對(duì)于a[i]利凑,我們就往左右遍歷,這樣就能更方便去找到數(shù)字嫌术。

typedef long long lld;

class Solution {
   static const int N = 4010100;
   lld a[N];
   pair<lld, lld> b[N];
   
public:
   void solve() {
       int t;
       cin >> t;
       while (t--) {
           int n, k;
           cin >> n >> k;
           
           for (int i = 0; i < n; ++i) cin >> a[i];
           sort(a, a + n);
           
           if (k >= 3) {
               cout << 0 << endl;
           }
           else if (k == 2) {
               int cnt = 0;
               for (int i = 0; i < n; ++i) {
                   b[cnt].first = a[i];
                   b[cnt].second = 0;
                   cnt++;
               }
               
               for (int i = 0; i < n; ++i) {
                   for (int j = i + 1; j < n; ++j) {
                       b[cnt].first = abs(a[i] - a[j]);
                       b[cnt].second = 1;
                       ++cnt;
                   }
               }
               
               sort(b, b + cnt);
               
               lld ans = a[0];
               for (int i = 0; i < cnt; ++i) {
                   ans = min(ans, b[i].first);
                   if (b[i].second == 0) { // 數(shù)組a來(lái)匹配最近的一個(gè)數(shù)字
                       int x = i, y = i;
                       while (x > 0) {
                           --x;
                           if (b[x].second == 1) break;
                       }
                       
                       while (y < cnt - 1) {
                           ++y;
                           if (b[y].second == 1) break;
                       }
                       if (x != i) {
                           ans = min(ans, abs(b[i].first - b[x].first));
                       }
                       if (y != i) {
                           ans = min(ans, abs(b[i].first - b[y].first));
                       }
                   }
               }
               
               cout << ans << endl;
           }
           else if (k == 1) {
               lld ans = a[0];
               for (int i = 1; i < n; ++i) ans = min(ans, min(a[i], a[i] - a[i - 1]));
               cout << ans << endl;
           }
       }
   }
}
ac;

題目4

題目鏈接
題目大意:
給出n個(gè)整數(shù)的數(shù)組a和b哀澈,現(xiàn)在可以對(duì)數(shù)組a進(jìn)行操作:
選擇數(shù)組內(nèi)任意區(qū)間[l, r],將區(qū)間[l, r]內(nèi)的整數(shù)都改為區(qū)間的最大值度气。
比如割按,對(duì)于數(shù)組[1, 2, 3, 4, 5],選擇區(qū)間[1, 3]進(jìn)行操作磷籍,則會(huì)生成[3, 3, 3, 4, 5]适荣;

現(xiàn)在想知道丙躏,數(shù)組a是否可以進(jìn)行若干次上面的操作,最終變成數(shù)組b束凑。

輸入:
第一行晒旅,整數(shù)?? 表示t個(gè)樣例 ?? (1≤??≤10000)
每個(gè)樣例3行
第1行整數(shù) n (1≤n≤1000)
第2行整數(shù) ??1,??2,…,???? (1≤????≤??)
第3行整數(shù) ??1,??2,…,???? (1≤????≤??)

輸出:
每個(gè)樣例一行,如果可行則輸出YES汪诉,如果不可行則輸出NO废恋;

Examples
input
5
5
1 2 3 2 4
1 3 3 2 4
5
3 4 2 2 4
3 4 3 4 4
5
3 2 1 1 1
3 3 3 2 2
2
1 1
1 2
3
1 1 2
2 1 2

output
YES
NO
YES
NO
NO

題目解析:
從數(shù)據(jù)量較小的情況開(kāi)始分析,比如說(shuō)n=2時(shí)扒寄,數(shù)組數(shù)字可以簡(jiǎn)化成1和2鱼鼓;
那么就會(huì)有[1,2]和[2,2],比較容易得到結(jié)果该编;
當(dāng)n=3時(shí)迄本,我們?cè)黾觽€(gè)數(shù)組3,如果放在數(shù)組[1,2]左右兩邊课竣,對(duì)結(jié)果不影響嘉赎;但是如果放在中間,數(shù)組[1, 3, 2]是無(wú)法變成[2, 3, 2]于樟;
由此我們可以知道公条,較大的數(shù)字會(huì)阻斷較小的數(shù)字傳遞;
當(dāng)n=4時(shí)迂曲,我們可以看到一個(gè)有意思的樣例:
1,2,3,4
3,4,4,4
數(shù)字3靶橱,跨過(guò)第2個(gè)數(shù)字影響到了第1個(gè)數(shù)字,然后第2路捧、3個(gè)數(shù)字最終又被數(shù)字4覆蓋关霸。
由此我們可以知道,數(shù)字的影響是最終可能非間隔杰扫,但是必須傳遞過(guò)去队寇,并且中間路徑可能被更大數(shù)字覆蓋。

至此涉波,我們的思路就清晰起來(lái):
1英上、從小到大來(lái)枚舉數(shù)字,因?yàn)楫?dāng)x覆蓋過(guò)某個(gè)數(shù)字后啤覆,只有x+1才能覆蓋這個(gè)覆蓋;
2惭聂、每一個(gè)數(shù)字窗声,都可以向左右蔓延,蔓延條件有兩個(gè)辜纲,隔壁數(shù)字小于等于當(dāng)前數(shù)字笨觅,隔壁數(shù)字對(duì)應(yīng)的數(shù)組b元素要大于等于當(dāng)前數(shù)字拦耐;
3、重復(fù)上面所有的過(guò)程见剩,直到所有數(shù)字結(jié)束杀糯;

這里的核心依據(jù),就是通過(guò)數(shù)組b的元素作為數(shù)組a元素的上限苍苞,盡可能讓每一個(gè)數(shù)組a元素去變大固翰。

思考:
當(dāng)N的范圍再擴(kuò)大1000倍呢?上面的這個(gè)做法在效率上就會(huì)不足羹呵,但是思路可以沿用擴(kuò)展骂际。
首先回顧這里的耗時(shí)操作,首先是枚舉數(shù)字從小到大冈欢,然后找到和這個(gè)位置對(duì)應(yīng)的數(shù)字歉铝,簡(jiǎn)單實(shí)現(xiàn)是O(N^2)的復(fù)雜度,但是我們先預(yù)處理一遍數(shù)組凑耻,記錄每個(gè)數(shù)字對(duì)應(yīng)的下標(biāo)太示,這樣就可以做到O(N)的復(fù)雜度;
其次是在數(shù)字覆蓋的過(guò)程中香浩,有時(shí)會(huì)出現(xiàn)每個(gè)位置被重復(fù)覆蓋多次的情況先匪,但是對(duì)于結(jié)果而言,我們只需要知道某個(gè)位置不匹配時(shí)(a[i] != b[i])弃衍,它應(yīng)該往數(shù)組a左邊/右邊去找到等于b[i]的元素呀非。
這個(gè)過(guò)程,同樣可以預(yù)處理镜盯。
比如說(shuō)對(duì)于下面的樣例岸裙,當(dāng)a[3] != b[3],我們要往數(shù)組a兩邊去找數(shù)組元素等于3的情況速缆;
3 3 2 1 4 3 3
3 3 3 3 4 3 3
首先在前面的預(yù)處理步驟降允,我們記錄每一個(gè)數(shù)字的位置,那么對(duì)于數(shù)字3艺糜,我們同樣記錄了3在數(shù)組a的位置為[0,1,5,6]剧董,這樣我們很容易知道對(duì)于a[3]而言,最近數(shù)字3位置在a[1]和a[5]破停;

接下來(lái)的問(wèn)題是翅楼,對(duì)于某個(gè)位置i和某個(gè)位置j,是否能夠匹配真慢?
還是用上面的樣例毅臊,我們才用采樣這樣的策略:
1、對(duì)于數(shù)組a黑界,我們從小到大枚舉的元素的過(guò)程管嬉,我們把枚舉過(guò)的數(shù)字(包括當(dāng)前數(shù)字)皂林,在數(shù)組a出現(xiàn)的位置都用1來(lái)標(biāo)明;(某個(gè)位置為1蚯撩,表示該位置可以延伸)
2础倍、對(duì)于數(shù)組b,我們從小到大枚舉的元素的過(guò)程胎挎,我們把還沒(méi)有枚舉過(guò)的數(shù)字(包括當(dāng)前數(shù)字)沟启,在數(shù)組b出現(xiàn)的位置都用1來(lái)標(biāo)明;(某個(gè)位置為1呀癣,表示該位置可以延伸)
樣例數(shù)據(jù)
3 3 2 1 4 3 3
3 3 3 3 4 3 3
就可以轉(zhuǎn)義為
1 1 1 1 0 1 1
1 1 1 1 1 1 1
這樣美浦, 當(dāng)我們?cè)谂袛郺[1]和a[3]是否能夠匹配時(shí),其實(shí)就是判斷數(shù)組a區(qū)間[1, 3]的數(shù)字和是否為3项栏,并且數(shù)組b區(qū)間[1,3]的數(shù)字和是否為3浦辨;

那么如何做快速的標(biāo)記、以及計(jì)算累加和呢沼沈?
1流酬、標(biāo)記問(wèn)題,通過(guò)預(yù)處理我們能O(1)獲取對(duì)應(yīng)位置列另,并且每個(gè)數(shù)字我們只會(huì)標(biāo)記一次芽腾,所以總的標(biāo)記復(fù)雜度是O(N);
2页衙、計(jì)算累加和摊滔,在一個(gè)數(shù)組里面,可以對(duì)某些元素進(jìn)行數(shù)值修改店乐、然后要求區(qū)間和艰躺,可以用線(xiàn)段樹(shù)來(lái)解決。


class Solution {
    static const int N = 201010;
    int a[N], b[N];
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            for (int i = 0; i < n; ++i) cin >> a[i];
            for (int i = 0; i < n; ++i) cin >> b[i];
            for (int k = 1; k <= n; ++k) {
                for (int i = 0; i < n; ++i) {
                    if (a[i] == k) {
                        int x = i - 1, y = i + 1;
                        while (x >= 0 && a[x] <= k && k <= b[x]) {
                            a[x] = k;
                            --x;
                        }
                        while (y < n && a[y] <= k && k <= b[y]) {
                            a[y] = k;
                            ++y;
                        }
                    }
                }
            }
            int ans = 1;
            for (int i = 0; i < n; ++i) ans = ans && (a[i] == b[i]);
            cout << (ans ? "YES" : "NO") << endl;
        }
    }
}
ac;

題目5

題目鏈接
題目大意:
有n個(gè)正整數(shù)的數(shù)組a眨八,現(xiàn)在Alice和Bob在玩游戲腺兴,Alice先操作,Bob再操作廉侧;
Alice會(huì)移除數(shù)組中页响,最多k個(gè)元素;
Bob會(huì)將數(shù)組中段誊,最多x個(gè)元素乘以-1闰蚕;

每個(gè)人只行動(dòng)一次,Alice想要讓最終數(shù)組的元素和盡可能大枕扫,Bob想要讓數(shù)組的元素和盡可能信汶纭;
問(wèn)最終的數(shù)字和為多少烟瞧;

輸入:
第一行诗鸭,整數(shù)?? 表示t個(gè)樣例 ?? (1≤??≤10000)
每個(gè)樣例2行
第一行,整數(shù)?? , ?? , and ?? (1≤??≤2?1e5 , 1≤??,??≤?? )
第二行参滴,n個(gè)整數(shù)??1,??2,…,???? (1≤????≤1000)

輸出:
每個(gè)樣例一行强岸,輸出最終的數(shù)字和;

Examples
input
8
1 1 1
1
4 1 1
3 1 2 4
6 6 3
1 4 3 2 5 6
6 6 1
3 7 3 3 32 15
8 5 3
5 5 3 3 3 2 9 9
10 6 4
1 8 2 9 3 3 4 5 3 200
2 2 1
4 3
2 1 2
1 3

output
0
2
0
3
-5
-9
0
-1

題目解析:
由于題目有k和x兩個(gè)變量砾赔,我們先考慮x=1個(gè)數(shù)字的情況蝌箍;
假設(shè)題目數(shù)據(jù)已經(jīng)從大到小排序,數(shù)組還是a暴心,以4妓盲、3、2专普、1為例悯衬;
先考慮bob的操作(為什么是先考慮后手?因?yàn)檫@樣思考簡(jiǎn)單)
假設(shè)Alice沒(méi)有操作檀夹,那bob一定會(huì)選擇-4筋粗,也就是數(shù)組最大的元素;(如果x=2炸渡,那么就是前2個(gè))

那么Alice如果操作呢娜亿?
移除4的好處是最終消除了-4,但是增加了-3蚌堵,同時(shí)移除原來(lái)正數(shù)3买决,總體的代價(jià)應(yīng)該是4-3-3=-2,所以Alice不操作結(jié)果更佳吼畏;

由此可知道數(shù)組排序后督赤,Alice如果移除,一定是移除前面若干個(gè)數(shù)字宫仗;Bob的負(fù)數(shù)操作够挂,也一定是前面x個(gè)數(shù)字。
那么只需要枚舉下k=0藕夫、1孽糖、2、3毅贮、办悟、、k的情況滩褥,對(duì)應(yīng)的結(jié)果病蛉。(邊界情況比較容易些錯(cuò),可以直接模擬,簡(jiǎn)化過(guò)程)

注意:
一些特殊case
k=2, x=2
4+3+2+1
-4-3+2+1=-4
-3-2+1=-4
-2-1=-3

k=2, x=2
6+6+3.5+1
-6-6-+4.5=-7.5
-3.5-1=-4.5

typedef long long lld;
 
class Solution {
    static const int N = 201010;
    lld a[N], sum[N];
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n, k, x;
            cin >> n >> k >> x;
            for (int i = 0; i < n; ++i) cin >> a[i];
            sort(a, a + n, greater<int>());
            sum[0] = a[0];
            // [left, mid, right]
            // left是移除铺然,mid是負(fù)數(shù)俗孝,right是剩下
            lld leftSum = 0, midSum = 0, rightSum = 0;
            for (int i = 0; i < x; ++i) midSum += a[i];
            for (int i = x; i < n; ++i) rightSum += a[i];
            lld ans = rightSum - midSum;
            for (int remove = 1; remove <= k; ++remove) {
                midSum -= a[remove - 1]; //移除當(dāng)前這個(gè)數(shù)字
                if (remove + x <= n) {
                    // 右邊還有剩余
                    midSum += a[remove + x - 1]; // midSum增加這個(gè)數(shù)字
                    rightSum -= a[remove + x - 1]; // rightSum移除這個(gè)數(shù)字
                }
                ans = max(ans, rightSum - midSum);
            }
            cout << ans << endl;
        }
    }
}
ac;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市魄健,隨后出現(xiàn)的幾起案子赋铝,更是在濱河造成了極大的恐慌,老刑警劉巖沽瘦,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件革骨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡析恋,警方通過(guò)查閱死者的電腦和手機(jī)良哲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)助隧,“玉大人筑凫,你說(shuō)我怎么就攤上這事±洌” “怎么了漏健?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)橘霎。 經(jīng)常有香客問(wèn)我蔫浆,道長(zhǎng),這世上最難降的妖魔是什么姐叁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任瓦盛,我火速辦了婚禮,結(jié)果婚禮上外潜,老公的妹妹穿的比我還像新娘原环。我一直安慰自己,他們只是感情好处窥,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布嘱吗。 她就那樣靜靜地躺著,像睡著了一般滔驾。 火紅的嫁衣襯著肌膚如雪谒麦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天哆致,我揣著相機(jī)與錄音绕德,去河邊找鬼。 笑死摊阀,一個(gè)胖子當(dāng)著我的面吹牛耻蛇,可吹牛的內(nèi)容都是我干的踪蹬。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼臣咖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼跃捣!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起亡哄,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤枝缔,失蹤者是張志新(化名)和其女友劉穎布疙,沒(méi)想到半個(gè)月后蚊惯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灵临,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年截型,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儒溉。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宦焦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顿涣,到底是詐尸還是另有隱情波闹,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布涛碑,位于F島的核電站精堕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蒲障。R本人自食惡果不足惜歹篓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揉阎。 院中可真熱鬧庄撮,春花似錦、人聲如沸毙籽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坑赡。三九已至烙如,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垮衷,已是汗流浹背厅翔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搀突,地道東北人刀闷。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親甸昏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子顽分,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容