其他分享
首页 > 其他分享> > Cow and Treats 题解

Cow and Treats 题解

作者:互联网

Cow and Treats 题解

题目大意

在一年成功的牛奶生产后,Farmer John 奖励他的奶牛们它们最喜欢的美味的草。

在田里有 \(n\) 个单位的排成一行的草,每个单位的草有甜味 \(s_i\)。Farmer John 有 \(m\) 头奶牛,每只都有最喜欢的甜味 \(f_i\) 和饥饿值 \(h_i\)。他想要在奶牛选取两个不相交的子集,分别在这行草的左侧和右侧排成一列。注意两边站多少奶牛是无关紧要的。

奶牛会按以下方式被喂:

注意草不会长回来。并且为了防止奶牛沮丧,Farmer John 不必保证喂了所有奶牛。

惊人的是,Farmer John 已经发现睡着的奶牛是最满足的。如果 Farmer John 安排的最优。求出最多的睡着的奶牛数,并求出在此情况下有多少种左右两侧奶牛的方案 Farmer John 可以选择(对 \(10^9+7\) 取模)。只要这个方案存在一种顺序使得能不让奶牛沮丧即可,Farmer John 具体如何安排是无关紧要的。

\(n,m\le 5000\)

解题思路

首先,我们容易发现一个性质。

每种颜色的奶牛在序列中最多只会出现两次(一次从左边出发,另一次从右边出发)

我们枚举一个分界点 \(i\) ,表示从第一头出发的奶牛是从左边出发的,且它到达的位置

然后对于每个分解点,我们对每种颜色分开处理,最后按照草排列的顺序安排奶牛进入的顺序

显然,从右边出发的奶牛最多走到 \(i+1\)

设\(slm_s\)表示从左边到当前枚举点 \(i\) 的甜味为 \(s\)的草的个数,\(srm_s\) 表示从右边到 \(i+1\) 的甜味为 \(s\) 的草的个数,\(num[f][h]\) 表示要吃不多于 \(h\) 个单位甜味为 \(f\) 的草的牛的个数

首先考虑甜味为 \(s_i\) 的草,设 \(x=s_i\)

从左边走满足有 \(num[x][slm_x]-num[x][slm_x-1]\)头奶牛符合条件

从右边走满足条件的牛有 \(num[x][srm_x]\)头奶牛。但是如果 \(srm_x>=slm_x\),左边派出的奶牛也可能在右边被派出,方案就重复了,所以右边满足的条件的牛数量应为 \(num[x][srm_x]\)

设左边满足条件的牛的数量为 \(sl\) ,右边为 \(sr\)。

如果 \(sl=0\) 则不可能有满足条件的方案,直接跳过

如果 \(sr=0\) 则该方案只能贡献一头奶牛,方案数为 \(sl\)

否则 方案数为 \(sl*sr\) ,能贡献两头奶牛

接下来考虑其他甜味的草。

对于颜色 \(j\) ,从左边走满足要求的有 \(num[j][slm_j]\) 头,从右边走有 \(num[j][srm_j]\)头

接下来就很显然了,就不讲了

有一点是,当两边的符合条件的牛的数量都 \(>=2\) 时,方案数为 \(sl*sr-min(sl,sr)\),这和我们上面的哪个 \(sl*sr\) 形式其实是一样的

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
typedef long long ll;
using namespace std;
template<typename T>void read(T &x){
	x=0;int f(1);char c(getchar());
	for(;!isdigit(c);c=getchar())if(c=='-')f=-f;
	for(; isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c-'0');
	x*=f;
}
template<typename T>void write(T x){
	if(x<0)putchar('-'),x=-x;
	if(x/10)write(x/10),x%=10;
	putchar(x+'0');
}
const ll mod=1000000007;
ll mo(ll a){
	return a>=mod?a-mod:a;
}
const int maxn=5005;
int num[maxn][maxn],slm[maxn],srm[maxn],s[maxn];
int main(){
	int n,m;
	read(n),read(m);
	for(int i=1;i<=n;++i)
		read(s[i]),++srm[s[i]];
	for(int i=1;i<=m;++i){
		int f,h;
		read(f),read(h);
		++num[f][h];
	}
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			num[i][j]+=num[i][j-1];
	ll anssum=1,ansnum=0;
	for(int i=0;i<=n;++i){
		if(i)++slm[s[i]],--srm[s[i]];
		ll testsum=1,testnum=0;int sl,sr;
		if(i){
			sl=slm[s[i]],sr=srm[s[i]];
			sr=num[s[i]][sr]-(sr>=sl);
			sl=num[s[i]][sl]-num[s[i]][sl-1];
			if(!sl)continue;
			if(sr)testsum=testsum*sl*sr%mod,testnum+=2;
			else testsum=testsum*sl%mod,testnum++;
		}
		for(int j=1;j<=n;++j){
			if(j==s[i])continue;
			sl=slm[j],sr=srm[j];
			sr=num[j][sr],sl=num[j][sl];
			if(!sl&&!sr)continue;
			if(!sl||!sr)testsum=testsum*(sl+sr)%mod,testnum++;
			else if(sr==1&&sl==1)
				testsum=testsum*2%mod,testnum++;
			else testsum=testsum*(sl*sr-min(sl,sr))%mod,testnum+=2;
		}
		if(testnum>ansnum)
			ansnum=testnum,anssum=testsum;
		else if(testnum==ansnum)
			anssum=mo(anssum+testsum)%mod;
	}
	write(ansnum),putchar(' ');
	if(ansnum)write(anssum),putchar('\n');
	else puts("1");
	return 0;
}

标签:John,Treats,Cow,题解,Farmer,num,sl,奶牛,甜味
来源: https://www.cnblogs.com/CHK666/p/15413350.html