CF1295F Good Contest / [APIO2016] 划艇

先離散化,設 \(f_i\) 爲考慮前 \(i\) 個元素的方案數,枚舉第 \(i\) 個元素處在第 \(j\) 個區間,同時枚舉一塊兒在第 \(j\) 個區間的元素個數,用組合數計算方案數,\(DP\) 過程當中處理組合數就是 \(O(n^3)\) 了。c++

第一題要算 \(n\) 個元素放到值域爲 \(m\) 的區間中造成不降序列的方案數,第二題要算 \(n\) 個元素放到值域爲 \(m\) 的區間中造成嚴格遞增序列的方案數,且每一個元素能夠不選,但最後一個元素必須選,第一題的不降序列其實就是隨便放,用隔板法便可獲得 \(\binom{n+m-1}{m-1}\),轉化一下第二題的模型就能發現其方案數和第一題同樣,也能夠推導證實:git

\[\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} \]

第一題:spa

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

第二題:code

#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;
}
相關文章
相關標籤/搜索