nowcoder 提高组模拟赛 选择题 解题报告
選擇題
鏈接:
https://www.nowcoder.com/acm/contest/178/B
來源:??途W
題目描述
有一道選擇題,有 \(a,b,c,d\) 四個選項。
現在有 \(n\) 個人來做這題,第 \(i\) 個人有 \(p_{i,j}\) 的概率選第 \(j\) 個選項。
定義 \(cnt(x)\) 為選第 \(x\) 個選項的人數。
令 \(mx\) 為 \(cnt(x)\) 最大的 \(x\) (如果有多個\(cnt(x)\)最大的 \(x\),則取其中 \(x\) 最小的),
若\(cnt(mx) \le \lfloor\frac{n}{2}\rfloor\) ,則所有人得 \(0\) 分;
否則令 \(choice_i\) 表示第 \(i\) 個人選的選項,則第 \(i\) 人得\(w_{mx,choice_i}\)分
求每個人的期望得分。
輸入描述:
第一行一個整數 \(n\) ,表示人數。
接下來 \(n\) 行,每行 \(4\) 個整數,其中第 \(i\) 行第 \(j\) 個數表示 \(p_{i,j}\) ,即在模 \(998244353\) 意義下第 \(i\) 個人選第 \(j\) 個選項的概率。
接下來 \(4\) 行,每行 \(4\) 個整數,第 \(i\) 行第 \(j\) 個數表示 \(w_{i,j}\) 。
輸出描述:
共 \(n\) 行,第 \(i\) 行表示第 \(i\) 個人在模 \(998244353\) 意義下的期望得分。
備注:
全部的輸入數據滿足:
- \(1 ≤ n ≤ 2000\)
- $0 ≤ p_{i,j} < 998244353 (1 ≤ i ≤ n,1 ≤ j ≤ 4) $
- \(\sum\limits_{j=1}^4 p_{i,j} \equiv 1 (\bmod 998244353)(1\le i \le n)\)
各個測試點的性質如下
| \(1\) | \(\le 2\) | |
| \(2\) | \(\le 10\) | \(p_{i,3}=p_{i,4}=0,(1\le i \le n)\) |
| \(3\) | \(\le 10\) | |
| \(4,5\) | \(\le 100\) | \(p_{i,3}=p_{i,4}=0,(1\le i \le n)\) |
| \(6,7\) | \(\le 100\) | \(p_{i,4}=0(1\le i \le n)\) |
| \(8,9,10,11\) | \(\le 100\) | |
| \(12\sim20\) | \(\le 2000\) |
Solution
考試的時候打了55pts暴力,結果爆5了,原因竟然是出負數了沒模正。。
枚舉每個人選什么和最后結果是什么,然后算一下其他人的選擇對這個結果的概率。
每次可以簡單的\(n^2\)做\(dp\)
\(dp_{i,j}\)代表前\(i\)個人有\(j\)個選了的和
\(dp_{i,j}=dp_{i-1,j-1}p_{i,k}+dp_{i-1,j}(1-p_{i,k})\)
發現每次只是少了一個人不進行\(dp\)
可以先把所有人的\(dp\)搞出來,然后\(O(n)\)把人踢出來
具體的,設\(dp_{i}\)為\(i\)個人選了某選項的全集
枚舉每個人時,顯然有\(dp_i'=p_idp_{i-1}+(1-p_i)dp_i\)
那么回退時有\(dp_i=\frac{dp_i'-p_idp_{i-1}}{1-p_i}\)
注意壓維了的話是存在順序的,還要特判\(p_i=1\)
Code:
#include <cstdio> #define ll long long const int N=2e3+10; const ll mod=998244353ll; int n; ll p[N][5],w[5][5],dp[N][5],inv[N][5],ans[N]; ll quickpow(ll d,ll k) {ll f=1;d=(d%mod+mod)%mod;while(k){if(k&1) f=f*d%mod;d=d*d%mod;k>>=1;}return f; } int main() {scanf("%d",&n);for(int i=1;i<=n;i++)for(int j=1;j<=4;j++)scanf("%lld",&p[i][j]),inv[i][j]=quickpow(1-p[i][j],mod-2);for(int i=1;i<=4;i++)for(int j=1;j<=4;j++)scanf("%lld",&w[i][j]);dp[0][1]=dp[0][2]=dp[0][3]=dp[0][4]=1;for(int k=1;k<=4;k++)for(int i=1;i<=n;i++){ll p1=(1-p[i][k]),p2=p[i][k];for(int j=n;j;j--)dp[j][k]=(p2*dp[j-1][k]+p1*dp[j][k])%mod;dp[0][k]=dp[0][k]*(1-p[i][k])%mod;}for(int i=1;i<=n;i++)//這個人for(int j=1;j<=4;j++)//選啥{if(p[i][j]==0) continue;for(int k=1;k<=4;k++)//結果是{if(w[k][j]==0) continue;int flag=1,up=(n>>1)+1-(j==k);ll sum=0;if(p[i][k]==1) flag=0;if(flag){dp[0][k]=dp[0][k]*inv[i][k]%mod;ll p2=p[i][k];for(int l=1;l<up;l++)//退包dp[l][k]=(dp[l][k]-p2*dp[l-1][k])%mod*inv[i][k]%mod;for(int l=up;l<=n;l++){dp[l][k]=(dp[l][k]-p2*dp[l-1][k])%mod*inv[i][k]%mod;sum+=dp[l][k];}}if(!flag){for(int i=up+1;i<=n;i++)sum+=dp[i][k];}sum%=mod;(ans[i]+=w[k][j]*sum%mod*p[i][j])%=mod;if(flag){ll p1=(1-p[i][k]),p2=p[i][k];for(int l=n;l;l--)dp[l][k]=(dp[l][k]*p1+p2*dp[l-1][k])%mod;dp[0][k]=dp[0][k]*(1-p[i][k])%mod;}}}for(int i=1;i<=n;i++)printf("%lld\n",(ans[i]+mod)%mod);return 0; }2018.10.21
轉載于:https://www.cnblogs.com/butterflydew/p/9827273.html
總結
以上是生活随笔為你收集整理的nowcoder 提高组模拟赛 选择题 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第十四章 架构师领导艺术(待续)
- 下一篇: MySQL 快速入门教程