题目链接

(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<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<algorithm>
#include<vector>
#define llong long long
#define pll pair<llong,llong>
#define mkpr make_pair
using namespace std; const int N = 103680;
vector<pll> 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<<i)) {ret = quickmul(ret,cur,mod)%mod; y-=(1ll<<i);}
cur = quickmul(cur,cur,mod);
}
return ret;
} namespace Pollard_Rho
{
const int N = 15;
const int LGM = 64;
llong fc[LGM+2];
llong a[N+2];
llong m;
int n;
llong ans;
llong quickmul(llong x,llong y,llong mod=P)
{
llong tmp=(x*y-(llong)((long double)x/mod*y+1.0e-8)*mod)%mod;
return tmp<0 ? tmp+mod : tmp;
}
llong quickpow(llong x,llong y,llong mod=P)
{
llong cur = x,ret = 1ll;
for(int i=0; y; i++)
{
if(y&(1ll<<i)) {ret = quickmul(ret,cur,mod)%mod; y-=(1ll<<i);}
cur = quickmul(cur,cur,mod);
}
return ret;
}
llong gcd(llong x,llong y) {return y==0 ? x : gcd(y,x%y);}
llong absl(llong x) {return x>=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) return d;
if(t==y) return x;
if(i==k)
{
t = y;
k<<=1;
}
}
}
void factorize(llong x,llong c)
{
if(x==1) return;
if(Miller_Rabin(x))
{
n++; fc[n] = x;
return;
}
llong p = x,k = c;
while(p>=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<pfac.size(); i++) printf("(%lld,%lld) ",pfac[i].first,pfac[i].second); puts("");
ans = 0ll;
dfs(0,1ll,1ll);
printf("%lld\n",ans);
}
return 0;
}

BZOJ 5330 Luogu P4607 [SDOI2018]反回文串 (莫比乌斯反演、Pollard Rho算法)的更多相关文章

  1. [BZOJ5330][SDOI2018]反回文串

    luogu bzoj sol 枚举一个长度为\(n\)为回文串,它的所有循环位移都可以产生贡献. 但是这样算重了.重复的地方在于可能多个回文串循环同构,或者可能有的回文串经过小于\(n\)次循环位移后 ...

  2. [SDOI2018]反回文串

    题意 问有多少个长度为\(N\)且字符集大小为\(K\)的字符串可以通过回文串旋转 (把第一个字符移到最后)若干次得到.\(K\le N≤10^{18}\) 做法 ARC64F的加强版 设\(h(d) ...

  3. [BZOJ 5330][SDOI2018] 反回文串

    传送门 怎么说呢,一道不可多得的反演题吧,具体解释之后再补 #include <bits/stdc++.h> using namespace std; #define rep(i,a,b) ...

  4. Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法

    BZOJ 3667: Rabin-Miller算法 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 1044  Solved: 322[Submit][ ...

  5. 【SDOI2018】反回文串(【ARC064 F】Rotated Palindromes 加强版)

    题意 给你一个正整数 \(n\),求有多少字符集为 \(1\) 到 \(k\) 之间整数的字符串,使得该字符串可以由一个长度为 \(n\) 的回文串循环移位得到. ARC原题 \(100\%\) 的数 ...

  6. bzoj 2565: 最长双回文串

    Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同).输入 ...

  7. BZOJ 2565: 最长双回文串 [Manacher]

    2565: 最长双回文串 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1842  Solved: 935[Submit][Status][Discu ...

  8. [BZOJ]4755: [Jsoi2016]扭动的回文串

    Time Limit: 10 Sec  Memory Limit: 512 MB Description JYY有两个长度均为N的字符串A和B. 一个"扭动字符串S(i,j,k)由A中的第i ...

  9. 「SDOI 2018」反回文串

    题目大意: 求字符集大小为$k$长度为$n$的经循环移位后为回文串的数量. 题解: 这题是D1里最神的吧 考虑一个长度为$n$回文串,将其循环移位后所有的串都是满足要求的串. 但是显然这样计算会算重. ...

随机推荐

  1. 怎样创建并使用 vue 组件 (component) ?

    组件化开发 需要使用到组件, 围绕组件, Vue 提供了一系列功能方法, 这里仅记录组件的 最简单 的使用方法. 1. 通过 Vue.component(tagName, options) 注册一个 ...

  2. Datetime 在C#中的用法 获取当前时间的各种格式

    DateTime 获得当前系统时间: DateTime dt = DateTime.Now; Environment.TickCount可以得到“系统启动到现在”的毫秒值 DateTime now = ...

  3. 客户端相关知识学习(八)之Android“.9.png”

    参考 Android中.9图片的含义及制作教程 .9.png Android .9.png 的介绍

  4. vue实现吸顶

    data(){ return{ list:[], swiperOption:"", xiding : "", // 轮播高度 SwiperHeight:'' } ...

  5. eval的使用

    当逻辑字符串是拼接而成的时候可以用eval来判断真假 eg:let a= "22" let b = ">" let c = "1" 用 ...

  6. docker 安装ps命令

    apt-get update && apt-get install procps

  7. python连接postgres方法

    Python使用PyGreSQL操作PostgreSQL: import pg def operate_postgre_tbl_product(): try: #db = pg.connect(dbn ...

  8. Active Directory participation features and security extensions

    Participation in the Active Directory Samba 3.0 series, as well as the OS since Windows 2000, is pos ...

  9. 使用 jenkins 为 nginx 增加上下文

    每次需要在Nginx增加上下文,都需要添加如下两段 ​ server.conf upstream serverdownloadPage { server 10.11.19.6:3023; } ​ ht ...

  10. shell脚本基础和grep文本处理工具企业应用4

    文本处理工具:    egrep:        支持扩展的正则表达式实现类似于grep文本过滤功能:grep -E        egrep [OPTIONS] PATTERN [FILE...]  ...