zoukankan      html  css  js  c++  java
  • [loj3315]抽卡

    令$S$表示对于某一种抽卡顺序中某一段长度为$k$的段全部被抽到的时间(这里没有期望)所构成的集合,根据$min-max$容斥的公式,有$E(min(S))=sum_{Tsubseteq 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<jle 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}^{lfloorfrac{n}{k+1} floor}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
  • 相关阅读:
    【Beta阶段】第一次Scrum Meeting
    【Beta阶段】第二次Scrum Meeting
    【Beta阶段】第三次Scrum Meeting
    [BUAA软工]Alpha阶段事后分析
    [BUAA软工]Alpha阶段测试报告
    [北航软工]团队贡献分规则
    Windows Server 2008 R2之二从介质安装 AD DS
    Windows Server 2008 R2之一活动目录服务部署
    DC84问
    获取命令行指定参数
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13500699.html
Copyright © 2011-2022 走看看