zoukankan      html  css  js  c++  java
  • [cf794G]Replace All

    (本文中所有字符串都指非空字符串)

    第一部分:分析性质

    先考虑$c$和$d$中没有"?"的情况——

    若$c=d$,显然任意$(s,t)$都可行,答案即$(2^{n+1}-2)^{2}$

    下面来考虑$c e d$的情况,先来定义非空串$s$和$t$互素:

    $s$和$t$互素当且仅当记$d=gcd(|s|,|t|)$,有$forall 0le i<d,s_{i}=t_{i}$以及$s_{i}=s_{i+d},t_{i}=t_{i+d}$

    (即两者都以$d$为循环节长度,且循环节相同)

    结论:若$(s,t)$对于$c e d$是”好“的,必要条件为$s$和$t$互素

    对$|s|+|t|$归纳,来证明此结论在$|s|+|t|le k$时成立,则$|s|+|t|=k+1$时也成立

    删去$c$和$d$的最长公共前缀,此时两者开头字母不同,对$s$和$t$的长度分类讨论:

    1.若$|s|=|t|$,显然即有$s=t$,即互素

    2.若$|s|<|t|$,那么$s$必然为$t$的前缀,且设$t=s+t'$,不妨将$c$和$d$中的$B$替换为$AB$,得到新串$c'$和$d'$

    不难证明$c' e d'$(两者第2个字符必然不同)且$|s|+|t'|le k$,由于$gcd(|s|,|t|)=gcd(|s|,|t|-|s|)$,根据归纳可以得到$s$和$t$互素

    3.若$|s|>|t|$,与第2种情况类似,这里就不具体分析了

    另外,对于初始条件,即$|s|+|t|=2$时,显然有$|s|=|t|=1$,因此$s=t$,即互素

    另一方面,当$s$和$t$互素,最终的两个串也具有相同的循环节,因此只需要长度相同即可

    第二部分:分类讨论

    更具体的,记$a_{c},b_{c},a_{d},b_{d}$分别表示对应串中$A$和$B$的个数,即要$a_{c}|s|+b_{c}|t|=a_{d}|s|+b_{d}|t|$

    根据上述分析,以上两个条件即充要条件,下面来考虑答案——

    对$a_{c},b_{c},a_{d},b_{d}$的大小分类讨论,由于$|s|,|t|>1$,仅有以下三种情况:

    1.$a_{c}=a_{d}$且$b_{c}=b_{d}$

    2.$a_{c}>a_{d}$且$b_{c}<b_{d}$

    3.$a_{c}<a_{d}$且$b_{c}>b_{d}$(这种情况与第2种类似,以下不具体分析)

    在第一种情况下,我们可以通过交换使$c=d$,那么条件仅包含$s$和$t$互素

    根据定义,枚举$|s|$和$|t|$,对应的串即有$2^{gcd(|s|,|t|)}$种

    枚举$gcd$,进行莫比乌斯反演,即$sum_{d=1}^{n}2^{d}sum_{g=1}^{lfloorfrac{n}{d} floor}mu(g)(lfloorfrac{n}{dg} floor)^{2}$

    根据调和级数,暴力计算即可,时间复杂度为$o(nlog n)$

    在第二种情况下,同样通过交换,使得$a_{d}$个$A$和$b_{c}$个$B$抵消,最终$c$为$a_{c}-a_{d}$个$A$、$d$为$b_{d}-b_{c}$个$B$

    另一方面,前者条件即可以写作$(a_{c}-a_{d})|s|=(b_{d}-b_{c})|t|$,令$g=gcd(a_{c}-a_{d},b_{d}-b_{c})$,则$|s|$和$|t|$可以被描述为$|s|=frac{b_{d}-b_{c}}{g}k$以及$|t|=frac{a_{c}-a_{d}}{g}k$(其中$kin Z^{+}$,有$gcd(|s|,|t|)=k$)

    考虑枚举$1le kle lfloorfrac{ng}{max(a_{c}-a_{d},b_{d}-b_{c})} floor$,每一次的答案即$2^{k}$,求和后即$2^{lfloorfrac{ng}{max(a_{c}-a_{d},b_{d}-b_{c})} floor}-2$

    第三部分:统计答案

    令$c'$和$d'$为最终的串,$a_{c'},b_{c'},a_{d'},b_{d'}$定义类似,再定义$q_{c}$和$q_{d}$为$c$和$d$中"?"的个数

    枚举最终的$k=a_{c'}-a_{d'}$,显然即可确定$b_{d'}-b_{c'}=|d|-|c|+k$,然后根据分类讨论,算出此时的答案

    (对于$c=d$的情况,暂时将答案看作分类讨论中的第一种情况)

    下面,来统计有多少种"?"的填法能取到这个$k$,枚举$c$填了$i$个$a$,那么$d$中就要填$a_{c}+i-k-a_{d}$个$a$,进而根据组合数,即$sum_{i}{q_{c}choose i}{q_{d}choose a_{c}+i-k-a_{d}}$(关于$i$的范围,实际上当$i$过大或过小该式即为0)

    考虑将${q_{c}choose i}$变形为${q_{c}choose q_{c}-i}$,根据组合意义,即在$q_{c}+q_{d}$个数中选$q_{c}+a_{c}-k-a_{d}$个数(枚举了前$q_{c}$个数中选的数个数$i$),因此即${q_{c}+q_{d}choose q_{c}+a_{c}-k-a_{d}}$

    由此,将方案数乘上对应的答案并对所有$k$累加即可

    令$Delta=(2^{n+1}-2)^{2}-sum_{d=1}^{n}2^{d}sum_{g=1}^{lfloorfrac{n}{d} floor}mu(g)(lfloorfrac{n}{dg} floor)^{2}$,即每一次$c=d$时的答案差,乘上$c=d$的方案数并加入原答案中来修改$c=d$的答案即可

    总复杂度即为$o(nlog n)$,瓶颈是分类讨论中的第一种情况以及求最大公约数

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 300005
     4 #define mod 1000000007
     5 int n,ac,bc,qc,ad,bd,qd,C1,C2,ans,mi[N<<1],fac[N<<1],inv[N<<1],mu[N],p[N],vis[N];
     6 char s1[N],s2[N];
     7 int sqr(int k){
     8     return 1LL*k*k%mod;
     9 }
    10 int C(int n,int m){
    11     return 1LL*fac[n]*inv[m]%mod*inv[n-m]%mod;
    12 }
    13 int gcd(int x,int y){
    14     if (!y)return x;
    15     return gcd(y,x%y);
    16 }
    17 int main(){
    18     mi[0]=fac[0]=inv[0]=inv[1]=1;
    19     for(int i=1;i<(N<<1);i++)mi[i]=2*mi[i-1]%mod;
    20     for(int i=1;i<(N<<1);i++)fac[i]=1LL*i*fac[i-1]%mod;
    21     for(int i=2;i<(N<<1);i++)inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
    22     for(int i=1;i<(N<<1);i++)inv[i]=1LL*inv[i-1]*inv[i]%mod;
    23     mu[1]=1;
    24     for(int i=2;i<N;i++){
    25         if (!vis[i]){
    26             p[++p[0]]=i;
    27             mu[i]=-1;
    28         }
    29         for(int j=1;(j<=p[0])&&(i*p[j]<N);j++){
    30             vis[i*p[j]]=1;
    31             if (i%p[j])mu[i*p[j]]=-mu[i];
    32             else{
    33                 mu[i*p[j]]=0;
    34                 break; 
    35             }
    36         }
    37     }
    38     scanf("%s%s%d",s1,s2,&n);
    39     int l1=strlen(s1),l2=strlen(s2);
    40     for(int i=0;i<l1;i++){
    41         if (s1[i]=='A')ac++;
    42         if (s1[i]=='B')bc++;
    43         if (s1[i]=='?')qc++;
    44     }
    45     for(int i=0;i<l2;i++){
    46         if (s2[i]=='A')ad++;
    47         if (s2[i]=='B')bd++;
    48         if (s2[i]=='?')qd++;
    49     }
    50     C1=sqr(mi[n+1]+mod-2);
    51     for(int i=1;i<=n;i++){
    52         int s=0;
    53         for(int j=1;j<=n/i;j++)s=(s+1LL*(mu[j]+mod)*sqr(n/(i*j)))%mod;
    54         C2=(C2+1LL*mi[i]*s)%mod;
    55     }
    56     for(int i=ac-(ad+qd);i<=(ac+qc)-ad;i++){
    57         int s=C(qc+qd,qc+ac-i-ad),j=l2-l1+i;
    58         if ((i>0)&&(j<=0)||(i<0)&&(j>=0)||(!i)&&(j))continue;
    59         if (!i)ans=(ans+1LL*s*C2)%mod;
    60         else{
    61             int g=gcd(abs(i),abs(j));
    62             ans=(ans+1LL*s*(mi[n/(max(abs(i),abs(j))/g)+1]+mod-2))%mod;
    63         }
    64     }
    65     if (l1==l2){
    66         int s=1;
    67         for(int i=0;i<l1;i++){
    68             if ((s1[i]!='?')&&(s2[i]!='?')&&(s1[i]!=s2[i]))s=0;
    69             else{
    70                 if ((s1[i]=='?')&&(s2[i]=='?'))s=s*2%mod;
    71             }
    72         }
    73         ans=(ans+1LL*(C1+mod-C2)*s)%mod;
    74     }
    75     printf("%d",ans);
    76 } 
    View Code
  • 相关阅读:
    python爬虫之Anaconda安装
    python爬虫之scrapy安装(一)
    python爬虫之redis环境简单部署
    python爬虫之Phantomjs安装和使用
    python爬虫之win7Mongod安装使用
    python爬虫之PyQuery的基本使用
    python爬虫之xpath的基本使用
    python爬虫之git的使用(windows下pycharm使用)
    Sass教程
    Vue.js教程—1.介绍和安装
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14773099.html
Copyright © 2011-2022 走看看