题目:
分析:
O ( n 4 ) O(n^4) O(n4)的DP很容易能想到
定义 D P [ i ] [ j ] [ k ] DP[i][j][k] DP[i][j][k]表示第i个人选j时,有k个人比它小的概率
然后就能直接算期望了。
不过这玩意显然要T
发现,对于一个已经固定的i,j,那么剩下的所有人的所有情况本质上只有2种:比
A
i
,
j
A_{i,j}
Ai,j小,比
A
i
,
j
A_{i,j}
Ai,j大。
那么可以把每个人比它小的概率算出来,比它大的概率算出来,那么就可以看作一个多项式
P
0
+
P
1
x
P_0+P_1x
P0+P1x
显然,其他所有人的多项式之积就是它的dp值。
(此时就有同学会去想分治FFT了,还好这题模数不是NTT模数,不然估计我也得掉坑里去写NTT…)
考虑是否能有更好的方式维护这个多项式。
显然,我们可以按照 A i , j A_{i,j} Ai,j排序,这样每做一个,就只有一个多项式会改变。那么我们就能通过多项式除法去消除该多项式的影响。
由于该多项式一定只有2项,所以可以 ( O ( n ) ) (O(n)) (O(n))暴力除
总复杂度 O ( n 3 ) O(n^3) O(n3)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 210
#define MOD 1000000007
using namespace std;
typedef long long ll;
struct node{
int i,j;
ll A,G,P;
bool operator <(const node &a) const {
return A<a.A;
}
}ch[MAXN*MAXN];
int tot;
int M[MAXN];
ll inv100;
pair<ll,ll> now[MAXN];
ll F[MAXN],V[MAXN],ans[MAXN];
ll fsp(ll x,int y){
ll res=1;
while(y){
if(y&1)
res=res*x%MOD;
x=x*x%MOD;
y>>=1;
}
return res;
}
int n;
void dev(int x){
ll A=now[x].first,B=now[x].second;
ll A1=fsp(A,MOD-2),B1=fsp(B,MOD-2);
F[0]=F[0]*A1%MOD;
for(int i=1;i<n;i++)
F[i]=(F[i]-F[i-1]*B%MOD+MOD)*A1%MOD;
}
void mul(int x){
ll A=now[x].first,B=now[x].second;
for(int i=n-1;i>0;i--)
F[i]=(F[i]*A+F[i-1]*B)%MOD;
F[0]=F[0]*A%MOD;
}
int main(){
inv100=fsp(100,MOD-2);
SF("%d",&n);
for(int i=1;i<=n;i++){
SF("%d",&M[i]);
ll Q=0;
for(int j=1;j<=M[i];j++){
tot++;
SF("%d%d%d",&ch[tot].A,&ch[tot].G,&ch[tot].P);
ch[tot].G=100-ch[tot].G;
ch[tot].i=i,ch[tot].j=j;
Q+=ch[tot].P;
}
int inq=fsp(Q,MOD-2);
for(int j=1;j<=M[i];j++)
(ch[tot-M[i]+j].P*=inq)%=MOD;
}
for(int i=1;i<=n;i++)
SF("%lld",&V[i]);
reverse(V+1,V+1+n);
sort(ch+1,ch+1+tot);
F[0]=1;
for(int i=1;i<=n;i++)
now[i]=make_pair(1,0);
for(int id=1;id<=tot;id++){
int i=ch[id].i,j=ch[id].j;
int A=ch[id].A,G=ch[id].G,P=ch[id].P;
dev(i);
// PF("{%d %d}\n",i,j);
// for(int i=0;i<n;i++)
// PF("%lld ",F[i]);
// PF("\n");
for(int k=0;k<n;k++)
ans[i]=(ans[i]+P*F[k]%MOD*V[k+1]%MOD*ch[id].G%MOD*inv100%MOD)%MOD;
// PF("<%lld>\n",ans[i]);
now[i].first=(now[i].first-ch[id].P+MOD)%MOD;
now[i].second=(now[i].second+ch[id].P)%MOD;
// PF("<%lld %lld>\n",now[i].first,now[i].second);
mul(i);
// for(int i=0;i<n;i++)
// PF("%lld ",F[i]);
// PF("\n");
}
for(int i=1;i<=n;i++)
PF("%lld\n",ans[i]);
}