JZOJ4336. 【WC2016模拟】rabbit
题目描述:
这道题 的暴力就不说了。
对于 的部分分,写个网络流就可以过了。
对于 的部分分,可以贪心的对 从大到小排序,然后每次前 个数减一,注意要维护单调性,多维护区间最大值最小值可以解决(目的是找到-1后不单调的地方,把操作后移,因为保证前面单调,后面单调,所以都单调。。。
正解很巧妙。首先基于
的网络流
根据最大流最小割定理,最大流等于最小割。
我们考虑左边
连出的边的条数为
,右边连向
的边数为
,
为左边删去的边的总权值,
同理。如果使图不连通,那么重边要删去
条边。
所以总的价值就是
。
首先贪心的将
从小到大排序,保证
最小。枚举
,已知
,
和
,我们的目的是使
最小。
令
,易知
。因为前面保证
单调递增,所以差值单调递增。
不难看出
长这样:
也就是求当
时最大的
。
可以双指针。
这道题用桶排做到 ,但是因为我懒,直接用了 ,所以多了一只 。
#include <cstdio>
#include <cstring>
#include <algorithm>
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;
}