• 1307E


    1307E - Cow and Treats

    题意

    有一排给定口味的草,并且给m头牛,每个牛都只吃一种口味的草,并且要吃给定数量个。现在可以安排牛从两边出发,方向向另一方向进发,每次路过符合他口味的草就会吃,吃到他需要的数量就会停下开始睡觉,开始睡觉后就是个路障,不能通行。如果一个牛吃到了他需要的数量的草就会Happy,让你安排牛从两边走,求最大数量的happy牛的数量,并且求出满足最大数量情况下的方案数。方案的不同体现在集合的不同,比如从左边出发的牛集合不同,就算做不同方案。

    题解

    首先我们先来解决最大数量的问题。对于吃每一种口味的牛来说,同口味的牛,不能从同方向出发超过两只,显然可得,那么也就是说同一个口味的牛最多左边右边出发一只,也就是最多2只。对每一种牛求一下即可得最大口味数,本题的难点在于求方案数。这里要分左右n只有5000,一个很自然的想法是枚举从左和从右的分界线。假如从左开始到分界线一共有right[i]个i口味的草,那么需要吃的数量小于等于right[i]的牛都可以从这里出发,左边同理。我们设从左出发满足条件的牛有a个,从右有b个,那么从两边方案数量为a*b-min(a,b) 这里用的是容斥的思想。因为min(a,b),一定是max(a,b)的子集,所以可得。A交B的数量为min(a,b),从一边的方案数为(a+b)。从左到右枚举分界点算一遍即可。这里还要解决的是重复的问题,例如[1,10]区间假如[1,4] [7,10] 分别是两边行进的路径,那么[1,5][5,10] 就会把这个集合再算一遍,就重复了。怎么解决这个问题呢,我们可以考虑枚举每一个有牛休息的点,对于这个点,固定该点口味的牛,其他的点只要符合要求随意停留,这样就能不重不漏计算出方案数了。
    这里可以用upper_bound 很方便得找到符合条件的数量,同时用std::binary_search可以方便判断一个数在不在数组中。

    代码

    #include<bits/stdc++.h>
    #define pb push_back
    #define mkp make_pair
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=5000+5;
    int lefts[maxn],rights[maxn],num[maxn],ways[maxn],s[maxn];
    int n,m;
    vector<int>v[maxn];
    void solve1(int id){
    	int a=upper_bound(v[id].begin(),v[id].end(),rights[id])-v[id].begin();
    	int b=upper_bound(v[id].begin(),v[id].end(),lefts[id])-v[id].begin();
    	ll cnt2=a*b-min(a,b);//tow sides
    	ll cnt1=a+b;//one sides
    	if(cnt2>0){
    		ways[id]=cnt2;
    		num[id]=2;
    	}
    	else if(cnt1>0){
    		ways[id]=cnt1;
    		num[id]=1;
    	}
    	else {
    		ways[id]=1;
    		num[id]=0;
    	}
    }
    ll ans_tot=-1,ans_ways=1;
    ll add(ll a,ll b ){
    	a=(a+mod)%mod,b=(b+mod)%mod;
    	return (a+b+mod)%mod;
    }
    void update(ll tmp_tot,ll tmp_ways){
    	if(tmp_tot>ans_tot){
    		ans_tot=tmp_tot;
    		ans_ways=tmp_ways;
    	}
    	else if(tmp_tot==ans_tot){
    		ans_ways=add(ans_ways,tmp_ways);
    	}
    }
    void solve2(int id){
    	int a=upper_bound(v[id].begin(),v[id].end(),rights[id])-v[id].begin();
    	if(rights[id]>=lefts[id])//因为同一种口味同1数量的牛不可能有2个 所以固定一个在边界睡觉后 如果right[id]>=left[id] 既这个牛也满足从左边出发,只需要减掉他即可
    		a--;
    	if(a>0){
    		ways[id]=a;
    		num[id]=2;
    	}
    	else {
    		ways[id]=1;
    		num[id]=1;
    	}
    }
    ll mul(ll a,ll b){
    	a=(a+mod)%mod;
    	b=(b+mod)%mod;
    	return (a%mod)*(b%mod)%mod;
    }
    ll fpow(ll a,ll b){
    	ll ans=1;
    	while(b){
    		if(b&1)ans=mul(ans,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return ans;
    }
    ll inv(ll x){
    	return fpow(x,mod-2);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)scanf("%d",&s[i]),rights[s[i]]++;
    	for(int i=1;i<=m;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		v[x].push_back(y);
    	}
    	for(int i=1;i<=m;i++)sort(v[i].begin(),v[i].end());
    	for(int i=1;i<=n;i++){
    		solve1(i);
    	}
    	ll tmp_tot=0,tmp_ways=1;
    	for(int i=1;i<=n;i++){
    		tmp_tot+=num[i];
    		tmp_ways=mul(tmp_ways,ways[i]);
    	}
    	update(tmp_tot,tmp_ways);
    	//cout<<ans_tot<<" "<<ans_ways<<endl;
    	for(int i=1;i<=n;i++){
    		tmp_tot-=num[s[i]];
    		tmp_ways=mul(tmp_ways,inv(ways[s[i]]));
    		//cout<<"??? "<<tmp_ways<<endl;
    		rights[s[i]]--,lefts[s[i]]++;
    		if(binary_search(v[s[i]].begin(),v[s[i]].end(),lefts[s[i]])){
    			solve2(s[i]);
    			update(tmp_tot+num[s[i]],mul(tmp_ways,ways[s[i]]));
    
    			//cout<<i<<" "<<lefts[s[i]]<<"  "<<tmp_tot+num[s[i]]<<"  "<<ways[s[i]]<<endl;
    			//cout<<ans_tot<<" zzz "<<ans_ways<<endl;
    		}
    		solve1(s[i]);
    		tmp_tot+=num[s[i]];
    		//cout<<ways[s[i]]<<endl;
    		tmp_ways=mul(tmp_ways,ways[s[i]]);
    	}
    	printf("%lld %lld
    ",ans_tot,ans_ways);
    	return 0;
    }
    
    
  • 相关阅读:
    每天一个linux命令:top命令
    docker入门实战笔记
    Linux top里面%CPU和us%的解释
    mac开发环境配置
    TCP/IP及内核参数优化调优
    在C#中使用代理的方式触发事件(转,这篇应该是最好的)
    如何在Vista IIS 7 中用 vs2005 调试 Web 项目? (转)
    C#接口慨述
    asp跟asp.net的区别
    解耦的故事(一)tmfc的开关(转)
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/12372422.html
Copyright © 2020-2023  润新知