1. 程式人生 > 實用技巧 >[loj3315]抽卡

[loj3315]抽卡

令$S$表示對於某一種抽卡順序中某一段長度為$k$的段全部被抽到的時間(這裡沒有期望)所構成的集合,根據$min-max$容斥的公式,有$E(\min(S))=\sum_{T\subseteq S}(-1)^{|T|+1}E(\max(T))$(其中$E(\min(S))$即為答案) 求$E(\max(T))$,設$k$表示$T$中所對應的段所覆蓋的卡片數量,那麼$E(\max(T))$顯然只與$k$的大小有關,問題即在$m$張卡片中選出指定的$k$張卡片期望步數 每次抽中$k$張卡片中新卡片,都需要期望$\frac{m}{k-i}$(i為以抽走的卡片)步,因此得到$E(\max(T))=\sum_{i=1}^{k}\frac{m}{i}$ 當$T$中同時有以$i$和$j$為開頭的段且$i+1<j\le i+k$,那麼這些$T$的總貢獻一定為0($i+1$選與不選相互抵消),因此有貢獻的段一定是長度為$k$或$k+1$的段且不能相鄰或相交 為了更好的構造,放寬一些限制,允許$k+1$的段與後面的段相鄰,顯然這一部分的貢獻為0,不影響答案 構造:將長度為$n$的一段中選出若干段不相交的長度為$k+1$的段,然後將其中任意段的結尾刪除,容易證明這樣必然能構造出所有解且不會重複 設生成函式為$g_n(x)$,即$x^{i}$的係數為覆蓋了$i$個位置的$(-1)^{|T|}$之和,則有$g_{n}(x)=\sum_{i=0}^{\lfloor\frac{n}{k+1}\rfloor}c(n-ik,i)\cdot (x^{k+1}-x^{k})^{i}$ 解釋一下這個式子:$i$列舉段數,組合數即在選中的位置前再補上$k$個數,$(x^{k+1}-x^{k})^{i}$中$x^{k+1}$有兩段即貢獻為1,而$x^{k}$為一段即貢獻為-1 但$[n-k+1,n]$無法通過這種構造選擇,不妨強制選擇最後$k$個,所對應的生成函式為$-x^{k}g_{n-k}(x)$($g_{n}(x)$僅表示這種構造下的和,因此恰好不能再選擇$[n-2k+1,n-k]$) 設原序列中每一個連續段長度為$l_{i}$,那麼問題相當於要求$-\sum_{i=k}^{m}\prod_{j=1}^{t}(g_{l_{j}}(x)-x^{k}g_{l_{j}-k}(x))[i])\cdot \sum_{j=1}^{i}\frac{m}{i}$ 問題即如何求出$g_{n}(x)$,直接$o(\frac{m^{2}}{k^{2}})$暴力求就可以了,這些多項式相乘可以用分治ntt或不斷選擇最小的兩個合併(哈夫曼樹)來卡常就可以過了
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 200005
  4 #define mod 998244353
  5 struct poly{
  6     int n;
  7     vector<int>a;
  8 }o,t[N];
  9 priority_queue<pair<int,int> >q;
 10 int n,m,k,ans,a[N],fac[N],inv[N],f[N],rev[N<<1];
 11 int c(int n,int
m){ 12 return 1LL*fac[n]*inv[m]%mod*inv[n-m]%mod; 13 } 14 int ksm(int n,int m){ 15 if (!m)return 1; 16 int s=ksm(n,m>>1); 17 s=1LL*s*s%mod; 18 if (m&1)s=1LL*s*n%mod; 19 return s; 20 } 21 poly add(poly x,poly y){ 22 if (x.n<y.n)swap(x,y); 23 for
(int i=0;i<=y.n;i++)x.a[i]=(x.a[i]+y.a[i])%mod; 24 return x; 25 } 26 poly left(poly x,int k){ 27 poly y; 28 y.n=x.n+k; 29 for(int i=0;i<k;i++)y.a.push_back(0); 30 for(int i=0;i<=x.n;i++)y.a.push_back(x.a[i]); 31 return y; 32 } 33 poly mul(poly x,int k){ 34 poly y;
35 y.n=x.n; 36 for(int i=0;i<=y.n;i++)y.a.push_back(1LL*x.a[i]*k%mod); 37 return y; 38 } 39 poly ntt(poly x,int m,int p){ 40 for(int i=0;i<m;i++) 41 if (i<rev[i])swap(x.a[i],x.a[rev[i]]); 42 for(int i=2;i<=m;i*=2){ 43 int t=(i>>1),s=ksm(3,(mod-1)/i); 44 if (p)s=ksm(s,mod-2); 45 for(int j=0;j<m;j+=i) 46 for(int k=0,w=1;k<t;k++,w=1LL*w*s%mod){ 47 int y=1LL*w*x.a[j+k+t]%mod; 48 x.a[j+k+t]=(x.a[j+k]+mod-y)%mod; 49 x.a[j+k]=(x.a[j+k]+y)%mod; 50 } 51 } 52 if (p) 53 for(int i=0;i<m;i++)x.a[i]=1LL*x.a[i]*ksm(m,mod-2)%mod; 54 return x; 55 } 56 poly mul(poly x,poly y){ 57 int m=1; 58 while (m<=x.n+y.n)m*=2; 59 for(int i=0;i<m;i++)rev[i]=((rev[i>>1]>>1)|((i&1)*m/2)); 60 for(int i=x.n+1;i<m;i++)x.a.push_back(0); 61 x=ntt(x,m,0); 62 for(int i=y.n+1;i<m;i++)y.a.push_back(0); 63 y=ntt(y,m,0); 64 for(int i=0;i<m;i++)x.a[i]=1LL*x.a[i]*y.a[i]%mod; 65 x.n+=y.n; 66 return ntt(x,m,1); 67 } 68 poly mi(int k){ 69 poly ans; 70 ans.n=k; 71 for(int i=0;i<=k;i++)ans.a.push_back(c(k,i)); 72 for(int i=k-1;i>=0;i-=2)ans.a[i]=mod-ans.a[i]; 73 return ans; 74 } 75 poly calc(int n){ 76 poly ans; 77 ans.n=0; 78 ans.a.push_back(0); 79 for(int i=0;i<=n/(k+1);i++)ans=add(ans,left(mul(mi(i),c(n-i*k,i)),i*k)); 80 return ans; 81 } 82 int main(){ 83 scanf("%d%d",&n,&k); 84 fac[0]=inv[0]=inv[1]=1; 85 for(int i=1;i<=n;i++)fac[i]=1LL*fac[i-1]*i%mod; 86 for(int i=2;i<=n;i++)inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; 87 for(int i=1;i<=n;i++)f[i]=(f[i-1]+1LL*n*inv[i])%mod; 88 for(int i=1;i<=n;i++)inv[i]=1LL*inv[i-1]*inv[i]%mod; 89 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 90 sort(a+1,a+n+1); 91 for(int i=1,j=1;i<=n;i=j){ 92 for(;(j<=n)&&(a[j]+1==a[j+1]);j++); 93 j++; 94 if (j-i>=k){ 95 t[++m]=add(calc(j-i),mul(left(calc(j-i-k),k),mod-1)); 96 q.push(make_pair(-t[m].n,m)); 97 } 98 } 99 for(int i=1;i<m;i++){ 100 int x=q.top().second; 101 q.pop(); 102 int y=q.top().second; 103 q.pop(); 104 t[x]=mul(t[x],t[y]); 105 q.push(make_pair(-t[x].n,x)); 106 } 107 int x=q.top().second; 108 for(int i=k;i<=t[x].n;i++)ans=(ans+1LL*t[x].a[i]*f[i])%mod; 109 printf("%d",mod-ans); 110 }
View Code