• [atARC061F]Card Game for Three


    记录每一次操作的玩家为操作序列(去掉第一次),需要满足:$a$的个数为$n$且以$a$为结尾,$b$和$c$的个数分别不超过$m$和$k$

    其所对应的概率:每一个字符恰好确定一张卡牌,因此即$3^{n+m+k-|s|}$

    暴力枚举$b$和$c$的个数,即$sum_{i=0}^{m}sum_{j=0}^{k}{n+i+j-1choose i}{n+j-1choose j}3^{m+k-i-j}$

    将组合数用阶乘展开,即$sum_{i=0}^{m}sum_{j=0}^{k}frac{(n+i+j-1)!3^{m+k-i-j}}{(n-1)!i!j!}$

    枚举$i+j=s$,即$frac{sum_{s=0}^{m+k}(n+s-1)!3^{m+k-s}sum_{0le ile m,0le s-ile k}frac{1}{i!(s-i)!}}{(n-1)!}$

    关于后者显然是一个多项式乘法的形式,但由于模数是$10^{9}+7$,需要写一个拆系数fft/三模数ntt,复杂度为$o(nlog n)$且常数较大

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 300005
     4 #define M (1<<20)
     5 #define mod 1000000007
     6 #define K 40000
     7 #define cd complex<double>
     8 #define PI acos(-1.0)
     9 int n,m,k,ans,fac[M],inv[N],mi[M],rev[M];
    10 cd a1[M],a2[M],b1[M],b2[M],c1[M],c2[M],c3[M],w[M];
    11 void fft(cd *a,int p){
    12     for(int i=0;i<M;i++)
    13         if (i<rev[i])swap(a[i],a[rev[i]]);
    14     for(int i=2;i<=M;i<<=1)
    15         for(int j=0;j<M;j+=i)
    16             for(int k=0;k<(i>>1);k++){
    17                 cd s=w[(i>>1)+k];
    18                 if (p)s=conj(s);
    19                 cd x=a[j+k],y=a[j+k+(i>>1)]*s;
    20                 a[j+k]=x+y;
    21                 a[j+k+(i>>1)]=x-y;
    22             }
    23     if (p){
    24         for(int i=0;i<M;i++)a[i]/=M;
    25     }
    26 }
    27 int main(){
    28     fac[0]=inv[0]=inv[1]=mi[0]=1;
    29     for(int i=1;i<M;i++)fac[i]=1LL*fac[i-1]*i%mod;
    30     for(int i=2;i<N;i++)inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
    31     for(int i=2;i<N;i++)inv[i]=1LL*inv[i-1]*inv[i]%mod;
    32     for(int i=1;i<M;i++)mi[i]=3LL*mi[i-1]%mod;
    33     scanf("%d%d%d",&n,&m,&k);
    34     for(int i=0;i<M;i++)rev[i]=(rev[i>>1]>>1)+((i&1)*(M>>1));
    35     for(int i=1;i<M;i<<=1)
    36         for(int j=0;j<i;j++)w[i+j]=cd(cos(j*PI/i),sin(j*PI/i));
    37     for(int i=0;i<=m;i++)a1[i]=cd(inv[i]/K,0);
    38     for(int i=0;i<=m;i++)a2[i]=cd(inv[i]%K,0);
    39     for(int i=0;i<=k;i++)b1[i]=cd(inv[i]/K,0);
    40     for(int i=0;i<=k;i++)b2[i]=cd(inv[i]%K,0);
    41     fft(a1,0);
    42     fft(a2,0);
    43     fft(b1,0);
    44     fft(b2,0);
    45     for(int i=0;i<M;i++){
    46         c1[i]=a1[i]*b1[i];
    47         c2[i]=a1[i]*b2[i]+a2[i]*b1[i];
    48         c3[i]=a2[i]*b2[i];
    49     }
    50     fft(c1,1);
    51     fft(c2,1);
    52     fft(c3,1);
    53     for(int i=0;i<=m+k;i++){
    54         int s1=llround(c1[i].real())%mod;
    55         int s2=llround(c2[i].real())%mod;
    56         int s3=llround(c3[i].real())%mod;
    57         int s=(1LL*K*K%mod*s1+1LL*K*s2+s3)%mod;
    58         ans=(ans+1LL*fac[n+i-1]*mi[m+k-i]%mod*s)%mod;
    59     }
    60     ans=1LL*ans*inv[n-1]%mod;
    61     printf("%d",ans);
    62 }
    View Code

    事实上还有更好的做法,由于$frac{1}{i!(s-i)!}=frac{{schoose i}}{s!}$,代入即$frac{sum_{s=0}^{m+k}s!(n+s-1)!3^{m+k-s}sum_{0le ile m,0le s-ile k}{schoose i}}{(n-1)!}$

    考虑后者,也就是$sum_{i=l}^{r}{schoose i}$,定义为$f(s,l,r)$,我们将这一行的每一个数乘以2(即有2个),在将非首尾的数利用杨辉三角合并,即$2f(s,l,r)=f(s,l+1,r)+{schoose l}+{schoose r}$

    利用这个式子,注意到每一次$s$增加区间两端点变化为为$o(1)$,就可以线性的完成,复杂度为$o(n)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 1000005
     4 #define mod 1000000007
     5 int n,m,k,ans,fac[N],inv[N],mi[N];
     6 int c(int n,int m){
     7     if (n<m)return 0;
     8     return 1LL*fac[n]*inv[m]%mod*inv[n-m]%mod;
     9 }
    10 int main(){
    11     fac[0]=inv[0]=inv[1]=mi[0]=1;
    12     for(int i=1;i<N;i++)fac[i]=1LL*fac[i-1]*i%mod;
    13     for(int i=2;i<N;i++)inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
    14     for(int i=2;i<N;i++)inv[i]=1LL*inv[i-1]*inv[i]%mod;
    15     for(int i=1;i<N;i++)mi[i]=3LL*mi[i-1]%mod;
    16     scanf("%d%d%d",&n,&m,&k);
    17     //l=max(s-k,0),r=min(m,s)
    18     int s=1,l=0,r=0;
    19     for(int i=0;i<=m+k;i++){
    20         if (i){
    21             s=((2*s%mod+mod-c(i-1,l))%mod+mod-c(i-1,r))%mod;
    22             l++;
    23             while (max(i-k,0)<l)s=(s+c(i,--l))%mod;
    24             while (l<max(i-k,0))s=(s+c(i,l++))%mod;
    25             while (r<min(m,i))s=(s+c(i,++r))%mod;
    26             while (min(m,i)<r)s=(s+c(i,r--))%mod;
    27         }
    28         ans=(ans+1LL*fac[n+i-1]*mi[m+k-i]%mod*s%mod*inv[i])%mod;
    29     }
    30     ans=1LL*ans*inv[n-1]%mod;
    31     printf("%d",ans);
    32 }
    View Code
  • 相关阅读:
    Splash wait() 方法
    Splash go() 方法
    Splash 对象方法
    短信接口文档
    WMS开发环境
    Eureka
    pom.xml settings.xml
    Druid
    EAI并发
    重启WMS服务
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14460385.html
Copyright © 2020-2023  润新知