CF1295F Good Contest / [APIO2016] 划艇

先离散化,设 \(f_i\) 为考虑前 \(i\) 个元素的方案数,枚举第 \(i\) 个元素处在第 \(j\) 个区间,同时枚举一起在第 \(j\) 个区间的元素个数,用组合数计算方案数,\(DP\) 过程中处理组合数就是 \(O(n^3)\) 了。

第一题要算 \(n\) 个元素放到值域为 \(m\) 的区间中形成不降序列的方案数,第二题要算 \(n\) 个元素放到值域为 \(m\) 的区间中形成严格递增序列的方案数,且每个元素可以不选,但最后一个元素必须选,第一题的不降序列其实就是随便放,用隔板法即可得到 \(\binom{n+m-1}{m-1}\),转化一下第二题的模型就能发现其方案数和第一题一样,也可以推导证明:

\[\large \sum_{i=1}^n \binom{n-1}{i-1}\binom{m}{i}=\sum_{i=0}^{n-1} \binom{n-1}{i}\binom{m}{m-i-1}=\binom{n+m-1}{m-1} \]

第一题:

#include<bits/stdc++.h>
#define maxn 110
#define p 998244353
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,tot;
ll val=1;
int l[maxn],r[maxn],s[maxn];
ll f[maxn],g[maxn];
ll inv(ll x)
{
    ll v=1,y=p-2;
    while(y)
    {
        if(y&1) v=v*x%p;
        x=x*x%p,y>>=1;
    }
    return v;
}
int main()
{
    read(n);
    for(int i=1;i<=n;++i)
    {
        read(l[i]),read(r[i]),r[i]++,val=val*inv(r[i]-l[i])%p;
        s[++tot]=l[i],s[++tot]=r[i];
    }
    sort(s+1,s+tot+1),tot=unique(s+1,s+tot+1)-s-1;
    for(int i=1;i<=n;++i)
        l[i]=lower_bound(s+1,s+tot+1,l[i])-s,r[i]=lower_bound(s+1,s+tot+1,r[i])-s;
    f[0]=1;
    for(int i=tot-1;i;--i)
    {
        g[0]=1;
        for(int j=1;j<=n;++j) g[j]=g[j-1]*(s[i+1]-s[i]+j-1)%p*inv(j)%p;
        for(int j=n;j;--j)
        {
            if(l[j]>i||r[j]<=i) continue;
            for(int k=j;k;--k)
            {
                if(l[k]<=i&&r[k]>i) f[j]=(f[j]+f[k-1]*g[j-k+1]%p)%p;
                else break;
            }
        }
    }
    printf("%lld",f[n]*val%p);
    return 0;
}

第二题:

#include<bits/stdc++.h>
#define maxn 1010
#define p 1000000007
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,tot;
ll ans;
int l[maxn],r[maxn],s[maxn];
ll f[maxn],g[maxn];
ll inv(ll x)
{
    ll v=1,y=p-2;
    while(y)
    {
        if(y&1) v=v*x%p;
        x=x*x%p,y>>=1;
    }
    return v;
}
int main()
{
    read(n);
    for(int i=1;i<=n;++i) read(l[i]),read(r[i]),s[++tot]=l[i],s[++tot]=++r[i];
    sort(s+1,s+tot+1),tot=unique(s+1,s+tot+1)-s-1;
    for(int i=1;i<=n;++i) l[i]=lower_bound(s+1,s+tot+1,l[i])-s,r[i]=lower_bound(s+1,s+tot+1,r[i])-s;
    f[0]=1;
    for(int i=1;i<tot;++i)
    {
        g[0]=1;
        for(int j=1;j<=n;++j) g[j]=g[j-1]*(s[i+1]-s[i]+j-1)%p*inv(j)%p;
        for(int j=n;j;--j)
            if(l[j]<=i&&r[j]>i)
                for(int k=j,t=0;k;--k)
                    t+=l[k]<=i&&r[k]>i,f[j]=(f[j]+f[k-1]*g[t]%p)%p;
    }
    for(int i=1;i<=n;++i) ans=(ans+f[i])%p;
    printf("%lld",ans);
    return 0;
}
posted @ 2021-02-26 11:26  lhm_liu  阅读(110)  评论(0编辑  收藏  举报