【2021上海省賽】補倆題
阿新 • • 發佈:2021-09-17
D. Zztrans 的班級合照
思路:
- 容易發現,同學們從從低到高來站隊,每次必須保證已經站在第一排的人數大於等於第二排的人數。
- 設\(dp[i][j]\)表示已經佔了i個人,有j個人站在第前排的概率。
- 為了避免重複計算,可以把相同的縮成一個點,最後的答案再乘以相同的個數的全排列。
- 還要列舉相同的幾個數放在前一排了多少個。
點選檢視程式碼
int a[N]; ll dp[5005][3000]; ll F[5005]; int book [N]; vector<int>ve; void init(){ F[0] = 1; for(int i=1;i<=N-5;i++) F[i] = F[i-1]*i%mod; } int main(){ int n; cin>>n; init(); for(int i = 1;i <= n; i ++) cin >> a[i],book[a[i]]++; for(int i = 1; i <= n;i++)if(book[i]) ve.push_back(book[i]); dp[0][0] = 1; int pre = 0; for(auto i:ve){ pre += i; for(int j = min(pre,n/2) ;j>=pre - j ; --j){//注意轉移順序 for(int k = 0; k<=i&&k<=j;k++){ dp[pre][j] = (dp[pre][j] + dp[pre-i][j-k])%mod; } } } ll ans = dp[n][n/2]; for(int i = 1; i<=n ;++i) ans =ans*F[book[i]]%mod; cout<<ans<<endl; return 0; }
B. 小 A 的卡牌遊戲
思路:
點選檢視程式碼
struct node{ int a,b,c; bool operator < (const node &B)const{ return a-b>B.a-B.b; } }A[N]; ll f[5005][5005]; int main(){ int n,a,b,c; cin>>n>>a>>b>>c; for(int i=1;i<=n;i++)cin>>A[i].a>>A[i].b>>A[i].c; sort(A+1,A+n+1); for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++){ f[i][j] = -1e18; } } f[0][0] = 0; for(int i=1;i<=n;i++){ for(int j = 0;j <= i;j++){ if(j) f[i][j] = f[i-1][j-1] + A[i].c; int res = i - j; if(res <= a) f[i][j] = max(f[i][j],f[i-1][j]+A[i].a); else f[i][j] = max(f[i][j],f[i-1][j]+A[i].b); } } cout<<f[n][c]<<endl; return 0; }