1. 程式人生 > 實用技巧 >[CF295C] Greg and Friends - dp

[CF295C] Greg and Friends - dp

Description

有一隻載重為 \(k \le 5\times10^3\) 的船在兩岸之間往返,有 \(n \le 50\) 個人要過河,每個人的體重只能使 \(50\)\(100\),問最少的來回次數以及對應的方案數。

Solution

\(f[i][j][0/1]\) 表示對岸已經有 \(i\)\(50\)\(j\)\(100\) 時最少的航行次數,\(g[i][j][0/1]\) 為對應的方案數

列舉本次走的 \(k,l\) 個數,利用組合數進行轉移即可

最多轉移 \(2n\) 輪一定能完事,複雜度 \(O(n^5)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 55;
const int dbg = 1;
const int mod = 1e9+7;

int n,m,a,b;
int f[N][N][2],g[N][N][2],nCr[N][N],e[N][N][2];

void readall()
{
    ios::sync_with_stdio(false);

    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int t;
        cin>>t;
        if(t==50) ++a;
        else ++b;
    }
}

void update(int a,int b,int &c,int &d,int &e)
{
    if(a<c)
    {
        c=a;
        d=b;
        e=1;
    }
    else if(a==c)
    {
        d+=b;
        d%=mod;
    }
}

void presolve()
{
    nCr[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        nCr[i][0]=1;
        for(int j=1;j<=i;j++)
        {
            nCr[i][j]=(nCr[i-1][j]+nCr[i-1][j-1])%mod;
        }
    }
}

void solve()
{
    memset(f,0x3f,sizeof f);
    f[0][0][0]=0;
    memset(g,0xff,sizeof g);
    g[0][0][0]=1;
    e[0][0][0]=1;
    for(int v=1;v<=2*n;v++)
    {
        for(int i=0;i<=a;i++)
        {
            for(int j=0;j<=b;j++)
            {
                for(int k=0;i+k<=a;k++)
                {
                    for(int l=0;j+l<=b;l++)
                    {
                        if(k==0&&l==0) continue;
                        if(k*50+l*100>m) continue;
                        update(f[i][j][0]+1,g[i][j][0]*nCr[a-i][k]%mod*nCr[b-j][l]%mod,f[i+k][j+l][1],g[i+k][j+l][1],e[i+k][j+l][1]);
                    }
                }
            }
        }
        for(int i=0;i<=a;i++)
        {
            for(int j=0;j<=b;j++)
            {
                for(int k=0;i-k>=0;k++)
                {
                    for(int l=0;j-l>=0;l++)
                    {
                        if(k==0&&l==0) continue;
                        if(k*50+l*100>m) continue;
                        update(f[i][j][1]+1,g[i][j][1]*nCr[i][k]%mod*nCr[j][l]%mod,f[i-k][j-l][0],g[i-k][j-l][0],e[i-k][j-l][0]);
                    }
                }
            }
        }
        if(f[a][b][1]<1e9)
        {
            cout<<f[a][b][1]<<endl<<g[a][b][1]<<endl;
            return;
        }
    }
    {
        cout<<-1<<endl<<0<<endl;
    }
}

signed main()
{
    readall();
    presolve();
    solve();
}