【JZOJ 省选模拟】Moorio Kart

题目

Description
由于目前可供奶牛们使用的约会网站并没有给 Farmer John 留下深刻印象,他决定推出一个基于新匹配算法的奶牛交友网站,该算法可基于公牛和母牛间的共同兴趣对公牛和母牛进行匹配。

Bessie 在寻找情人节 Barn Dance 的合作伙伴时,决定试用这个网站。在注册账户之后,FJ 的算法为他给出了一个长度为 N(1≤N≤10^6) 的匹配列表,列表上每头公牛接受她舞蹈邀请的概率为 p (0<p<1)。

Bessie 决定向列表中的一个连续区间内的奶牛发送邀请,但Bessie希望恰好只有一个奶牛接受邀请。请帮助 Bessie 求出恰好只有一个奶牛接受邀请的最大概率是多少。

Input
第一行输入一个整数 N。
接下来 N 行,每行包含一个整数,它的含义是 pi​ 乘以 10^6后的结果。

Output
请输出恰好只有一个奶牛接受邀请的最大概率乘以 10^6106 后向下取整后的结果。

Sample Input
3
300000
400000
350000

Sample Output
470000

样例的最优方案是向第二和第三只奶牛发送邀请。

Data Constraint
子任务:对于 25% 的数据,N≤4000 。

思路

其实就是给你一个森林,让你每一棵树选一条路径,组成一个环,使得环长≥Y ,求满足要求的树个数。
由于n只有1500,所以可以n^2求路径
然后就变成了问给你几个集合,从这些集合中每个集合选择一个数,问和≥Y 的方案和。这是一个简单背包问题。求方案和可以顺便求出。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1577,YY=2577,mod=1e9+7;
int n,m;
struct E
{
	int v,w,next;
}e[N<<1];
int ls[N],cnt;
void add(int u,int v,int w)
{
	e[++cnt]=(E){v,w,ls[u]},ls[u]=cnt;
}
int X,Y,fa[YY];
void clear()
{
	for(int i=1; i<=n; i++) fa[i]=i;
}
int gf(int u)
{
	return u==fa[u]?u:fa[u]=gf(fa[u]);
}
int cn,bl[N],num[N][YY],sum[N][YY];
void init(int u,int fr,int id)
{
	bl[u]=id;
	for(int i=ls[u]; i; i=e[i].next)
	{
		int v=e[i].v;
		if(v!=fr) init(v,u,id);
	}
}
void dfs(int u,int fr,int len)
{
	if(fr) (sum[bl[u]][min(Y,len)]+=len)%=mod,++num[bl[u]][min(Y,len)];
	for(int i=ls[u]; i; i=e[i].next)
	{
		int v=e[i].v;
		if(v!=fr) dfs(v,u,len+e[i].w);
	}
}
int de[YY][2],las[YY][2];
int fac(int u)
{
	int yjy=1;
	for(int i=2; i<=u; i++) yjy=(ll)yjy*i%mod;
	return yjy;
}
void solve()
{
	for(int i=1; i<=n; i++) if(gf(i)==i)++cn,init(i,0,cn);
	for(int i=1; i<=n; i++) dfs(i,0,0);
	int st=min(Y,X*cn);
	de[st][0]=1,de[st][1]=X*cn;
	for(int i=1; i<=cn; i++)
	{
		for(int j=st; j<=Y; j++) las[j][0]=de[j][0],las[j][1]=de[j][1],de[j][0]=de[j][1]=0;
		for(int j=0; j<=Y; j++) if(num[i][j]) for(int k=st; k<=Y; k++) if(las[k][0])
		{
			de[min(j+k,Y)][0]=(de[min(j+k,Y)][0]+(ll)las[k][0]*num[i][j])%mod;
			de[min(j+k,Y)][1]=(de[min(j+k,Y)][1]+(ll)las[k][0]*sum[i][j]+(ll)las[k][1]*num[i][j])%mod;
		}
	}
	printf("%lld\n",(ll)de[Y][1]*fac(cn-1)%mod*((mod+1)/2)%mod);
}

int main()
{
	freopen("mooriokart.in","r",stdin); freopen("mooriokart.out","w",stdout);
	scanf("%d%d%d%d",&n,&m,&X,&Y);
	clear();
	int u,v,w;
	for(int i=1; i<=m; i++) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w),fa[gf(u)]=gf(v);
	solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值