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<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算法)的更多相关文章
- [BZOJ5330][SDOI2018]反回文串
luogu bzoj sol 枚举一个长度为\(n\)为回文串,它的所有循环位移都可以产生贡献. 但是这样算重了.重复的地方在于可能多个回文串循环同构,或者可能有的回文串经过小于\(n\)次循环位移后 ...
- [SDOI2018]反回文串
题意 问有多少个长度为\(N\)且字符集大小为\(K\)的字符串可以通过回文串旋转 (把第一个字符移到最后)若干次得到.\(K\le N≤10^{18}\) 做法 ARC64F的加强版 设\(h(d) ...
- [BZOJ 5330][SDOI2018] 反回文串
传送门 怎么说呢,一道不可多得的反演题吧,具体解释之后再补 #include <bits/stdc++.h> using namespace std; #define rep(i,a,b) ...
- Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法
BZOJ 3667: Rabin-Miller算法 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 1044 Solved: 322[Submit][ ...
- 【SDOI2018】反回文串(【ARC064 F】Rotated Palindromes 加强版)
题意 给你一个正整数 \(n\),求有多少字符集为 \(1\) 到 \(k\) 之间整数的字符串,使得该字符串可以由一个长度为 \(n\) 的回文串循环移位得到. ARC原题 \(100\%\) 的数 ...
- bzoj 2565: 最长双回文串
Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同).输入 ...
- BZOJ 2565: 最长双回文串 [Manacher]
2565: 最长双回文串 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1842 Solved: 935[Submit][Status][Discu ...
- [BZOJ]4755: [Jsoi2016]扭动的回文串
Time Limit: 10 Sec Memory Limit: 512 MB Description JYY有两个长度均为N的字符串A和B. 一个"扭动字符串S(i,j,k)由A中的第i ...
- 「SDOI 2018」反回文串
题目大意: 求字符集大小为$k$长度为$n$的经循环移位后为回文串的数量. 题解: 这题是D1里最神的吧 考虑一个长度为$n$回文串,将其循环移位后所有的串都是满足要求的串. 但是显然这样计算会算重. ...
随机推荐
- 牛客 109B 好位置 (字符串水题)
大意: 给定字符串$s1,s2$, 对于$s1$中所有与$s2$相等的子序列$t$, $t$在$s1$中的下标定义为好位置. 求$s1$是否所有位置都是好位置. 显然$s1$的前缀要与$s2$相等, ...
- DevOps 之 Jenkins 安装、配置、美化、插件及常见错误处理
继续上一篇的话题,既然已经搭建了 GitLab 的代码仓库,那么现在就可以开始进行下一步持续集成环境的搭建了.公司准备利用 Jenkins CI 进行持续集成,本文记录了 Jenkins 的安装.基础 ...
- Java进阶开发-基于Base64的加密与解密操作
基于Base64的加密与解密操作 正常来讲加密基本上永远伴随着解密,所谓的加密或者解密往往都是需要有一些所谓的规则.在JDK1.8开始提供有一组新的加密处理操作,Base64处理.在这个类里面有两个内 ...
- QT获取屏幕分表率(PC、安卓)
QRect screenRect = QGuiApplication::primaryScreen()->geometry(); double devicePixelRatio = QGuiAp ...
- z-index神奇的失效了!!!
z-index简单介绍 首先z-index只对定位元素有效,什么是定位元素呢,也就是设置了position属性的元素,position:relative--相对定位,position:absolute ...
- JavaSE基础知识之继承
一.概述 继承描述的是事物之间的所属关系,这种关系是: is-a 的关系.例如,图中的兔子属于食草动物,食草动物又属于动物.继承可以使多种事物之间形成一种关系体系,让父类更通用,子类更具体. 1.1 ...
- 使用JavaFX开发桌面程序(一)
使用JavaFX开发桌面程序 注:我也是JAVA FX的初学者之一,自己在学习的时候踩了许多的坑,中文英文的资料查了不少,但是觉得FX技术和其他热门技术相比,教程还是太少了.这里就尽量做一点微小的贡献 ...
- PL/SQL Developer -> 下载 -> 安装 ->执行SQL -> 设置本地/远程连接
一 下载 点击进入 https://www.allroundautomations.com/bodyplsqldevreg.html 二 安装 4wkf7lzcb8amvke2rzeuclnk5emc ...
- 实现用一个QueryService支持多数据库访问
上图,是在服务端定义多个数据库,准备在客户端通过“联接名称”及“客户端服务名称”访问这些数据库. 基于实现的MultiDBQueryService,将其注册为一个指定客户端服务名称的服务,如下图: 这 ...
- 注解【Annotation】、反射
注解:Annotation是从JDK5.0开始引入的新技术.Annotation的作用:如果没有注解信息处理流程,则注解毫无意义)- 不是程序本身,可以对程序作出解释.(这一点,跟注释没什么区别)- ...