【模拟+数学】Codeforces Round #621 (Div. 1 + Div. 2) 1307E Cow and Treats

Cow and Treats

【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:

  • The cows from the left and right side will take turns feeding in an
    order decided by Farmer John.
  • When a cow feeds, it walks towards the other end without changing direction and eats grass of its favorite sweetness until it eats hi units.
  • The moment a cow eats hi units, it will fall asleep there, preventing further cows from passing it from both directions.
  • If it encounters another sleeping cow or reaches the end of the grass row, it will get upset. Farmer John absolutely does not want any cows to get upset.

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.

Input

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

Output two integers — the maximum number of sleeping cows that can result and the number of ways modulo 109+7.

Examples

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单位为止.
  • 一头母牛吃完hi单位的那一刻,它将在那里睡着,阻止其他牛通过.
  • 如果一头牛碰到其他牛或者走到路的尽头还没吃饱,会不高兴.

注意:没有牛fi和hi都相同.
吃饱睡着的牛最开心,不能有牛不开心,可以不把牛放出来。
也就是选一部分牛出来让他们都吃饱。
问最多选多少头,有多少种方法能让开心的牛数量最多(左侧和右侧的牛的集合不同视为不同方法,出发顺序不重要)。


解题思路

先想几个前提条件

  • fi相同的牛,不能从同一方向出发。
  • fi相同的牛,最多只能有两头从两个方向出发。
  • fi不同的牛,不可能睡在同一格子上。
  • 从同一方向出发的牛,必定fi不同且睡在不同格子上,即有唯一的顺序保证它们能从同一方向出发且互不干扰。
  • 需要确定每头牛的方向,是否吃草,但不需要考虑牛之间的顺序。题目用(左边出发的牛的集合和右边出发的牛的集合)来代表一种方法。

先想最多能选几头牛。
考虑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相同的牛只能从右往左走,另外还有些细节问题比如没有牛从左往右走怎么计算什么的就不说了。

啊,不知道我什么时候才能出出来这么有意思的题,今天依然是只会出签到题的菜鸡。


AC代码

#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;
}

你可能感兴趣的:(【模拟+数学】Codeforces Round #621 (Div. 1 + Div. 2) 1307E Cow and Treats)