【cf链接】
After a successful year of milk production, Farmer John is rewarding his cows with their favorite treat: tasty grass!
On the field, there is a row of n units of grass, each with a sweetness si. Farmer John has m cows, each with a favorite sweetness fi and a hunger value hi. He would like to pick two disjoint subsets of cows to line up on the left and right side of the grass row. There is no restriction on how many cows must be on either side. The cows will be treated in the following manner:
Note that grass does not grow back. Also, to prevent cows from getting upset, not every cow has to feed since FJ can choose a subset of them.
Surprisingly, FJ has determined that sleeping cows are the most satisfied. If FJ orders optimally, what is the maximum number of sleeping cows that can result, and how many ways can FJ choose the subset of cows on the left and right side to achieve that maximum number of sleeping cows (modulo 109+7)? The order in which FJ sends the cows does not matter as long as no cows get upset.
The first line contains two integers n and m (1≤n≤5000, 1≤m≤5000) — the number of units of grass and the number of cows.
The second line contains n integers s1,s2,…,sn (1≤si≤n) — the sweetness values of the grass.
The i-th of the following m lines contains two integers fi and hi (1≤fi,hi≤n) — the favorite sweetness and hunger value of the i-th cow. No two cows have the same hunger and favorite sweetness simultaneously.
Output two integers — the maximum number of sleeping cows that can result and the number of ways modulo 109+7.
input
5 2
1 1 1 1 1
1 2
1 3
output
2 2
input
5 2
1 1 1 1 1
1 2
1 4
output
1 4
input
3 2
2 3 2
3 1
2 1
output
2 4
input
5 1
1 1 1 1 1
2 5
output
0 1
Note
In the first example, FJ can line up the cows as follows to achieve 2 sleeping cows:
Cow 1 is lined up on the left side and cow 2 is lined up on the right side.
Cow 2 is lined up on the left side and cow 1 is lined up on the right side.
In the second example, FJ can line up the cows as follows to achieve 1 sleeping cow:
Cow 1 is lined up on the left side.
Cow 2 is lined up on the left side.
Cow 1 is lined up on the right side.
Cow 2 is lined up on the right side.
In the third example, FJ can line up the cows as follows to achieve 2 sleeping cows:
Cow 1 and 2 are lined up on the left side.
Cow 1 and 2 are lined up on the right side.
Cow 1 is lined up on the left side and cow 2 is lined up on the right side.
Cow 1 is lined up on the right side and cow 2 is lined up on the left side.
In the fourth example, FJ cannot end up with any sleeping cows, so there will be no cows lined up on either side.
安排m头牛吃草。
草是一排一共n格,每格的草都有一个甜度si,被吃掉就不会再长出来。
每头牛只吃甜度为fi的草并且只吃hi单位,吃饱就睡在当前格子上。
牛吃草有四条规则:
注意:没有牛fi和hi都相同.
吃饱睡着的牛最开心,不能有牛不开心,可以不把牛放出来。
也就是选一部分牛出来让他们都吃饱。
问最多选多少头,有多少种方法能让开心的牛数量最多(左侧和右侧的牛的集合不同视为不同方法,出发顺序不重要)。
先想几个前提条件
先想最多能选几头牛。
考虑fi,感觉可以按fi分类,分类后fi相同的最多只能取两头,从两边走,只要加起来草够吃就能取,取hi最小的两头就行;fi不同的,从同一个方向走是不影响,但前面fi相同的里面俩方向都走了.
于是想到把两个方向的分开考虑,如果我在中间造一堵墙,在墙确定的时候,对一个fi,取hi最小的两头牛模拟一下就知道了,枚举墙是O(n),枚举牛也是O(n),一共O(n^2),n是5000,ok.
扩展一下,求方法数,枚举墙,假设现在枚举到墙的位置是x,即从左向右允许走到x,从右向左允许走到x+1,对每一个fi,扫一遍fi对应的牛得到a头只能从左往右,b头只能从右往左,c头两边都可以,那么fi可以取两头牛的方法数是
a*b+a*c+b*c+c*(c-1)
如果上式值为0表示不能取两头牛,那可以取一头牛的方法数是
a+b+c*2
如果上式的值也等于0 ,那说明只能取0头牛,方法数是1。
不同的fi在确定墙的前提下互不影响,可以直接相乘。
以上方法还有一个问题(其实连样例都过不了),就是像样例1,墙在中间没有牛路过的地方时,不同的墙之间会有重复答案。这个也好解决,出现重复的原因是墙的位置没有牛睡觉,所以可以改成枚举第一头从左往右走的牛,它就相当于墙,然后对标之前的要把(从左向右允许走到x)改成(从左向右允许走到x-1),枚举fi时要把作为墙的那头牛去掉并且和它fi相同的牛只能从右往左走,另外还有些细节问题比如没有牛从左往右走怎么计算什么的就不说了。
啊,不知道我什么时候才能出出来这么有意思的题,今天依然是只会出签到题的菜鸡。
#include
#define LL long long
using namespace std;
const int maxn=5000+100;
const LL mod=1e9+7;
int a1[maxn];
vector<int> f[maxn],l[maxn],r[maxn];
int main()
{
int n,m,K,x,y,u,v;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a1[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
f[x].push_back(y);
}
for(int i=1;i<=n;i++)
{
if(f[i].size()==0) continue;
sort(f[i].begin(),f[i].end());
///from left
int cnt=0,now=0;
for(int j=1;j<=n;j++)
{
if(a1[j]==i)
{
cnt++;
if(cnt==f[i][now])
{
l[i].push_back(j);
now++;
if(now==f[i].size()) break;
}
}
}
while(f[i].size()>l[i].size()) l[i].push_back(n+1);
///from right
cnt=0,now=0;
for(int j=n;j>=1;j--)
{
if(a1[j]==i)
{
cnt++;
if(cnt==f[i][now])
{
r[i].push_back(j);
now++;
if(now==f[i].size()) break;
}
}
}
while(f[i].size()>r[i].size()) r[i].push_back(-1);
}
f[0].push_back(0);
l[0].push_back(0);
r[0].push_back(0);///all from right
LL max_size=0,max_ways=1;
for(int i1=0;i1<=n;i1++)
{
for(int j1=0;j1<f[i1].size();j1++)
{
int mid=l[i1][j1];/// [0,mid),(mid,n]
if(mid==n+1) continue;
LL sz=0,ways=1;
for(int i=1;i<=n;i++)
{
if(f[i].size()==0) continue;
LL a=0,b=0,c=0;
for(int j=0;j<f[i].size();j++)
{
if(l[i][j]<mid&&r[i][j]>mid) c++;
else if(l[i][j]<=mid) a++;
else if(r[i][j]>mid) b++;
}
if(i==i1&&i1!=0)
{
a=0;
b+=c;
c=0;
}
if(a*b+a*c+b*c+c*(c-1)>0)
{
sz+=2;
ways=(a*b+a*c+b*c+c*(c-1))%mod*ways%mod;
}
else if(a+b+c*2>0)
{
sz+=1;
ways=(a+b+c*2)%mod*ways%mod;
}
}
if(i1!=0) sz++;
if(max_size<sz)
{
max_size=sz;
max_ways=ways;
}
else if(max_size==sz)
{
max_ways=(max_ways+ways)%mod;
}
}
}
if(max_size==0) max_ways=1;
max_ways%=mod;
printf("%I64d %I64d\n",max_size,max_ways);
return 0;
}