BZOJ 5330 Luogu P4607 [SDOI2018]反回文串 (莫比乌斯反演、Pollard Rho算法)

题目链接

(BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=5330
(Luogu) https://www.luogu.org/problem/P4607

题解

首先观察一些性质。
一个回文串可以轮换产生多少个本质不同的串?周期那么多个。
可是有一种特殊情况,就是对于长度为偶数的回文串\(a=ss^Rss^Rss^R...ss^R\) (\(s^R\)表示\(s\)的reverse), 如果轮换位数恰好等于周期的一半,那么会产生\(a'=s^Rss^Rss^Rs...s^Rs\), 这是另一个回文串,因此会算重!
于是我们大胆猜测,设\(a\)的周期为\(T\), 则当\(T\)为偶数时对答案的贡献为\(\frac{T}{2}\), 否则为\(T\).
一个简单的证明是,串\(a\)轮换\(d\)位和轮换\(T-d\)位所得到的串互为reverse,若得到了回文串,那么\(d=T-d\).

那么现在我们的问题简化了: 设长度为\(n\)字符集为\(m\)周期为\(T\)的回文串有\(g(T)\)个,要求的就是\(\sum_{d|n}g(d)h(d)\), 其中\(h(d)\)为贡献。
现在考虑怎么算周期为\(T\)的回文串: 设\(G(T)\)表示有多少个回文串满足\(T\)是它的周期(但不是最小周期,即周期是\(T\)的因数),则\(G(T)=m^{\lceil \frac{T}{2}\rceil}\).
且有\(G(T)=\sum_{d|T}g(d)\), 由莫比乌斯反演可得\(g(T)=sum_{d|T}\mu(\frac{T}{d})G(d)\).
然后直接枚举因数裸求就可以得到54至60分(当然也可以\(g(T)=G(T)-\sum_{d|T}g(d)\), 但是这样由于复杂度较劣只有30至36分,期望得分是官方题解里给的)

\(n\le 10^{18}\)时,\(n\)的约数个数\(d(n)\le 103680\).
推式子: \(\sum_{d|n}\sum_{d'|d}G(d')\mu(\frac{d}{d'})h(d)=\sum_{d|n}\sum_{d'|\frac{n}{d}}G(d)\mu(d')h(dd')\)
观察式子,当\(d\)为奇数\(\frac{n}{d}\)为偶数时,每一个奇数都会和一个偶数配成一对,并且\(\mu\)值相反。因此这种情况对答案贡献为\(0\).
在其他情况下,一定满足\(h(dd')=h(d)d'\), 即\(\sum_{d|n}G(d)h(d)\sum_{d'|\frac{n}{d}}d'\mu(d')\)
考虑\(\sum_{d|n}d\mu(d)\)的组合意义,易得原式等于\(\sum_{d|n}G(d)h(d)\prod_{p|\frac{n}{d}}(1-p)\), 其中\(p\)为质数
DFS所有的质因数即可。

时间复杂度\(O(n^{\frac{1}{4}}\log n+d(n)\log n)\), 其中\(d(n)\)\(n\)的约数个数.

代码

#include
#include
#include
#include
#include
#include
#define llong long long
#define pll pair 
#define mkpr make_pair
using namespace std;

const int N = 103680;
vector pfac;
llong P;

llong quickmul(llong x,llong y,llong mod=P)
{
    return (x%mod)*(y%mod)%mod;
}
llong quickpow(llong x,llong y,llong mod=P)
{
    llong cur = x,ret = 1ll;
    for(int i=0; y; i++)
    {
        if(y&(1ll<=0 ? x : -x;}
    llong ssrand(llong x,llong c,llong y) {return (quickmul(x,x,y)+c)%y;}
    bool Miller_Rabin(llong x)
    {
        if(x==1) return false;
        if(x==2) return true;
        if((x&1)==0) return false;
        llong y = x-1,t = 0ll;
        while((y&1)==0) y>>=1,t++;
        for(int i=1; i<=5; i++)
        {
            llong bas = rand()%(x-1)+1;
            llong cur = quickpow(bas,y,x);
            for(int j=1; j<=t; j++)
            {
                llong tmp = quickmul(cur,cur,x);
                if(tmp==1 && cur!=1 && cur!=x-1) return false;
                cur = tmp;
            }
            if(cur!=1) return false;
        }
        return true;
    }
    llong pollard_rho(llong x,llong c)
    {
        llong i = 1,k = 2;
        llong y = rand()%(x-1)+1; llong t = y;
        while(true)
        {
            i++;
            y = ssrand(y,c,x);
            llong d = gcd(absl(t-y),x);
            if(d>1 && d=x) p = pollard_rho(p,c--);
        factorize(p,k); factorize(x/p,k);
    }
    void Factorize(llong _m)
    {
        m = _m;
        n = 0;
        factorize(m,120);
        sort(fc+1,fc+n+1);
        pfac.clear();
        for(int i=1; i<=n; i++)
        {
            if(fc[i]==fc[i-1]) {pfac[pfac.size()-1].second++;}
            else {pfac.push_back(mkpr(fc[i],1));}
        }
    }
}

llong n,m;
llong ans;

void dfs(int pos,llong x,llong coe)
{
    if(pos==pfac.size())
    {
        if((x&1ll) && (!((n/x)&1ll))) {return;}
        llong tmp = quickmul(coe,quickmul(quickpow(m,(x+1)>>1),(x&1)?x:(x>>1)));
        ans = (ans+tmp)%P;
        return;
    }
    for(int i=0; i<=pfac[pos].second; i++)
    {
        dfs(pos+1,x,i==pfac[pos].second?coe:quickmul(coe,(P+1-pfac[pos].first%P)));
        x = x*pfac[pos].first;
    }
}

int main()
{
    srand(time(NULL));
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&P);
        Pollard_Rho::Factorize(n);
//      for(int i=0; i

你可能感兴趣的:(BZOJ 5330 Luogu P4607 [SDOI2018]反回文串 (莫比乌斯反演、Pollard Rho算法))