【多项式】【DP】省选模拟51nod抽卡大赛

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/88787232

题目:

在这里插入图片描述

分析:

O ( n 4 ) O(n^4) 的DP很容易能想到

定义 D P [ i ] [ j ] [ k ] DP[i][j][k] 表示第i个人选j时,有k个人比它小的概率

然后就能直接算期望了。

不过这玩意显然要T

发现,对于一个已经固定的i,j,那么剩下的所有人的所有情况本质上只有2种:比 A i , j A_{i,j} 小,比 A i , j A_{i,j} 大。
那么可以把每个人比它小的概率算出来,比它大的概率算出来,那么就可以看作一个多项式 P 0 + P 1 x P_0+P_1x
显然,其他所有人的多项式之积就是它的dp值。

(此时就有同学会去想分治FFT了,还好这题模数不是NTT模数,不然估计我也得掉坑里去写NTT…)

考虑是否能有更好的方式维护这个多项式。

显然,我们可以按照 A i , j A_{i,j} 排序,这样每做一个,就只有一个多项式会改变。那么我们就能通过多项式除法去消除该多项式的影响。

由于该多项式一定只有2项,所以可以 ( O ( n ) ) (O(n)) 暴力除

总复杂度 O ( n 3 ) O(n^3)

#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]);
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/88787232