loj2541【PKUWC2018】猎人杀

 

 

  • 题解

    • 题目中的选择条件等价于正常选择所有猎人,而如果选到已经出局的猎人就继续选;
    • 这两种选法是一样的因为(设$W=\sum_{i=1}^{n}w_{i}$ , $X$为已经出局的猎人的$w$之和):
    • $P_{i} = \sum_{i=0}^{ \infty } {(\frac{X}{W})}^i \frac{w_{i}}{W}$
    •  $= \frac{w_{i}}{W} \sum_{i=0}^{ \infty } {(\frac{X}{W})}^i$
    • $ = \frac{w_{i}}{W} \frac{1}{1-\frac{X}{W}}$
    • $ = \frac{w_{i}}{W-X} $
    • 考虑枚举强制$S$集合$(1 \notin S)$中的人在1之后出局,设$X(S) = \sum_{i=2}^{n} [i \in S]w_{i}$;
    •  $ans = \sum_{S} {(-1)}^{|S|}  \sum_{i=0}^{ \infty }  (1-\frac{w_{1}+X(S)}{W})^i  \frac{w_{1}}{W} $
    • $ans  = \sum_{S} {(-1)}^{|S|} \frac{w_{1}}{w_{1}+X(S)} $
    • 考虑求这个式子:
    • $ans = \sum_{i=0}^{W} \frac{w_{1}}{w_{1}+i} \sum_{S} [X(S)==i] (-1)^{|S|}$
    • 用生成函数$\Pi_{i=2}^{n} (1-x^{w_{i}})$处理处后面的部分即可;
    • 时间复杂度:$O(Wlog^2 \ W)$
 1 #include<bits/stdc++.h>
 2 #define mod 998244353
 3 using namespace std;
 4 const int N=200010,M=20;
 5 int n,m,w[N],f[M][N],mx[M],L,len,sz,Wn[M][N],rev[N];
 6 char gc(){
 7     static char*p1,*p2,s[1000000];
 8     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
 9     return(p1==p2)?EOF:*p1++;
10 }
11 int rd(){
12     int x=0;char c=gc();
13     while(c<'0'||c>'9')c=gc();
14     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
15     return x;
16 }
17 int pw(int x,int y){
18     int re=1;
19     for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)re=1ll*re*x%mod;
20     return re;
21 }
22 void ntt(int*a,int f){
23     for(int i=0;i<len;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
24     for(int i=1;i<len;i<<=1){
25         int wn=Wn[!~f][i<<1];
26         for(int j=0;j<len;j+=i<<1){
27             int w=1;
28             for(int k=0;k<i;++k,w=1ll*wn*w%mod){
29                 int x=a[j+k],y=1ll*w*a[j+k+i]%mod;
30                 a[j+k]=(x+y)%mod,a[j+k+i]=(x-y+mod)%mod;
31             }
32         }
33     }
34     if(!~f){
35         int iv=pw(len,mod-2);
36         for(int i=0;i<len;++i)a[i]=1ll*a[i]*iv%mod;
37     }
38 }
39 void solve(int l,int r){
40     if(l==r){
41         mx[++sz]=w[l];
42         f[sz][0]=1;f[sz][w[l]]=mod-1;
43         for(int i=1;i<w[l];++i)f[sz][i]=0;
44         return ;
45     }
46     int mid=(l+r)>>1;
47     solve(l,mid),solve(mid+1,r);
48     int a=sz-1,b=sz;
49     m=mx[a]+mx[b];
50     for(L=0,len=1;len<=m;len<<=1,L++);
51     for(int i=1;i<len;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
52     for(int i=mx[a]+1;i<len;++i)f[a][i]=0;
53     for(int i=mx[b]+1;i<len;++i)f[b][i]=0;
54     ntt(f[a],1);ntt(f[b],1);
55     for(int i=0;i<len;++i)f[a][i]=1ll*f[a][i]*f[b][i]%mod;
56     ntt(f[a],-1);
57     mx[--sz]=m;
58 }
59 int main(){
60     #ifndef ONLINE_JUDGE
61     freopen("loj2541.in","r",stdin);
62     freopen("loj2541.out","w",stdout);
63     #endif
64     n=rd();
65     for(int i=1;i<=n;++i)w[i]=rd();
66     for(int i=1<<17;i;i>>=1){
67         Wn[0][i]=pw(3,(mod-1)/i);
68         Wn[1][i]=pw(Wn[0][i],mod-2);
69     }
70     solve(2,n);
71     int ans=0;
72     for(int i=0;i<=mx[1];++i){
73         ans=(ans + 1ll*f[1][i]*w[1]%mod*pw(i+w[1],mod-2)%mod)%mod;
74     }
75     cout<<(ans+mod)%mod<<endl;
76     return 0;
77 }
View Code

 

转载于:https://www.cnblogs.com/Paul-Guderian/p/10447274.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值