1. 程式人生 > >【bzoj4868】[Shoi2017]期末考試 前綴和

【bzoj4868】[Shoi2017]期末考試 前綴和

[1] con microsoft pre log mic 表示 div 描述

題目描述

有n位同學,每位同學都參加了全部的m門課程的期末考試,都在焦急的等待成績的公布。第i位同學希望在第ti天或之前得知所.有.課程的成績。如果在第ti天,有至少一門課程的成績沒有公布,他就會等待最後公布成績的課程公布成績,每等待一天就會產生C不愉快度。對於第i門課程,按照原本的計劃,會在第bi天公布成績。有如下兩種操作可以調整公布成績的時間:1.將負責課程X的部分老師調整到課程Y,調整之後公布課程X成績的時間推遲一天,公布課程Y成績的時間提前一天;每次操作產生A不愉快度。2.增加一部分老師負責學科Z,這將導致學科Z的出成績時間提前一天;每次操作產生B不愉快度。上面兩種操作中的參數X,Y,Z均可任意指定,每種操作均可以執行多次,每次執行時都可以重新指定參數。現在希望你通過合理的操作,使得最後總的不愉快度之和最小,輸出最小的不愉快度之和即可

輸入

第一行三個非負整數A,B,C,描述三種不愉快度,詳見【問題描述】; 第二行兩個正整數n,m(1≤n,m≤105),分別表示學生的數量和課程的數量; 第三行n個正整數ti,表示每個學生希望的公布成績的時間; 第四行m個正整數bi,表示按照原本的計劃,每門課程公布成績的時間。 1<=N,M,Ti,Bi<=100000,0<=A,B,C<=100000

輸出

輸出一行一個整數,表示最小的不愉快度之和。

樣例輸入

100 100 2
4 5
5 1 2 3
1 1 2 3 3

樣例輸出

6


題解

啥數據結構都沒有的sb題

我TM考場上這道sb題才拿了60分真TM喪心病狂。

讀懂題之後大概是NOIP普及組小學生都會。

直接枚舉最終時間,求出同學的不愉快度,然後根據A和B的大小關系決定是否應該調整,以及應該調整多少。使用一個前綴和維護時間和,並用兩個指針維護第一個大於當前時間的等待時間和公布時間。

代碼一點也不難,時間復雜度是$O(n)$的。

另外bzoj中說的$C=10^{18}$有誤,應為$10^{16}$。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
typedef long long ll;
ll x[N] , y[N] , sx[N] , sy[N];
int main()
{
	ll n , m , i , j , k , a , b , c , ans = 1ll << 62 , s1 , s2 , c1 , c2 , r = 0;
	scanf("%lld%lld%lld%lld%lld" , &a , &b , &c , &n , &m);
	for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &x[i]) , r = max(r , x[i]);
	for(i = 1 ; i <= m ; i ++ ) scanf("%lld" , &y[i]) , r = max(r , y[i]);
	sort(x + 1 , x + n + 1) , sort(y + 1 , y + m + 1);
	for(i = 1 ; i <= n ; i ++ ) sx[i] = sx[i - 1] + x[i];
	for(i = 1 ; i <= m ; i ++ ) sy[i] = sy[i - 1] + y[i];
	if(c >= 0x7fffffff) r = x[1];
	for(i = 1 , j = k = 0 ; i <= r ; i ++ )
	{
		while(j < n && x[j + 1] < i) j ++ ;
		while(k < m && y[k + 1] < i) k ++ ;
		s1 = i * k - sy[k] , s2 = sy[m] - sy[k] - i * (m - k) , c1 = c * (i * j - sx[j]);
		if(a >= b) c2 = s2 * b;
		else if(s1 >= s2) c2 = s2 * a;
		else c2 = s1 * a + (s2 - s1) * b;
		ans = min(ans , c1 + c2);
	}
	printf("%lld\n" , ans);
	return 0;
}

【bzoj4868】[Shoi2017]期末考試 前綴和