JZOJ4336. 【WC2016模拟】rabbit

JZOJ4336. 【WC2016模拟】rabbit

题目描述:
在这里插入图片描述
JZOJ4336. 【WC2016模拟】rabbit_第1张图片

这道题 10 p t s 10pts 10pts的暴力就不说了。

对于 30 p t s 30pts 30pts的部分分,写个网络流就可以过了。

对于 50 p t s 50pts 50pts的部分分,可以贪心的对 b b b从大到小排序,然后每次前 a i a_{i} ai个数减一,注意要维护单调性,多维护区间最大值最小值可以解决(目的是找到-1后不单调的地方,把操作后移,因为保证前面单调,后面单调,所以都单调。。。

正解很巧妙。首先基于 30 p t s 30pts 30pts的网络流
JZOJ4336. 【WC2016模拟】rabbit_第2张图片
根据最大流最小割定理,最大流等于最小割。
我们考虑左边 S S S连出的边的条数为 x x x,右边连向 T T T的边数为 y y y S a Sa Sa为左边删去的边的总权值, S b Sb Sb同理。如果使图不连通,那么重边要删去 ( m − x ) ( n − y ) (m-x)(n-y) (mx)(ny)条边。

所以总的价值就是 S a + S b + ( m − x ) ( n − y ) Sa+Sb+(m-x)(n-y) Sa+Sb+(mx)(ny)
首先贪心的将 a , b a,b a,b从小到大排序,保证 S a S b SaSb SaSb最小。枚举 x x x,已知 m m m n n n x x x,我们的目的是使 S b − ( m − x ) y Sb-(m-x)y Sb(mx)y最小。
f ( y ) = S b − ( m − x ) y f(y)=Sb-(m-x)y f(y)=Sb(mx)y,易知 f ( y ) − f ( y − 1 ) = b y − ( m − x ) f(y)-f(y-1)=b_{y}-(m-x) f(y)f(y1)=by(mx)。因为前面保证 b b b单调递增,所以差值单调递增。
不难看出 f f f长这样:
JZOJ4336. 【WC2016模拟】rabbit_第3张图片
也就是求当 b y − ( m − x ) < = 0 b_{y}-(m-x)<=0 by(mx)<=0时最大的 y y y
可以双指针。

这道题用桶排做到 O ( n ) O(n) O(n),但是因为我懒,直接用了 s o r t sort sort,所以多了一只 l o g log log

#include 
#include 
#include 
using namespace std;

const int N = 2500010;

long long n,m,a[N],b[N],suma[N],sumb[N],r,x,y;
long long ans = 0x3f3f3f3f3f3f3f3f;

int main()
{
	scanf("%lld%lld%lld%lld%lld%lld",&m,&n,&a[1],&x,&b[1],&y), r = n;
	for(int i = 1;i < m; ++ i) a[i + 1] = (a[i] * 58 + x) % (n + 1);
	for(int i = 1;i < n; ++ i) b[i + 1] = (b[i] * 58 + y) % (m + 1);
	sort(a + 1,a + 1 + m), sort(b + 1,b + 1 + n);
	
	for(int i = 1;i <= m; ++ i) suma[i] = suma[i - 1] + a[i];
	for(int i = 1;i <= n; ++ i) sumb[i] = sumb[i - 1] + b[i];
	
	for(int i = 0;i <= m; ++ i)
	{
		for(int j = r;j >= 0; -- j)
			if(b[j] <= (m - i)) { r = j; break; }
		ans = min(ans,suma[i] + sumb[r] + (m - i) * (n - r));
	}
	
	printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(好题)