[CF295C] Greg and Friends - dp
阿新 • • 發佈:2020-08-29
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(); }