[atARC064F]Rotated Palindromes

(长度为$n$的序列$a_{i}$,下标范围为$[0,n)$,且用字符串的方式即$a_{[l,r]}$来表示子区间)

定义一个长为$n$的序列$a_{i}$的周期为的$l$满足$l|n$且$\forall l\le i<n,a_{i}=a_{i+l}$(这里不同于普通周期的定义,普通周期定义是没有$l|n$这个要求的),最小正周期即为其中最小的正整数$l$

先考虑枚举一开始回文的$a_{i}$,再将其轮换来构造出所有$a_{i}$,可以证明具有这样两个性质:

1.若一个序列$a_{i}$是回文的,且$a_{i}$的最小正周期为$l$,则$a_{[0,l)}$也是回文的

2.若一个序列$a_{i}$是回文的,且$a_{i}$的最小正周期为$l$,分类讨论:

(1)若$l$为奇数,则将其轮换排列后,不存在与$a_{i}$不同的回文串

(2)若$l$为偶数,则将其轮换排列后,恰好存在一个与$a_{i}$相同的回文串

关于性质1,考虑$a_{[0,l)}=a_{[n-l,n)]}$即可,特别的,当$l=n$时显然也成立

关于性质2,下面来证明一下:

将$a_{i}$轮换后,当以$i\equiv j(mod\ l)$为起点时,两者是相同的,因此不妨假设起点在$[0,l)$中

若以$i$为起点($0<i<l$,当$i=0$时即$a_{i}$本身)时其为回文,不难得到$a_{k}=a_{i+(i-k)}=a_{2i-k}$(下标在模$n$意义下运算)

同时根据性质1,$a_{[0,l)}$自身回文,即$a_{k}=a_{2l-k}$,两式组合即$a_{k}=a_{2(l-i)+k}$

也就是说$2(l-i)$为$a_{i}$周期,同时$l$也是其周期,则$a_{i}$周期可以为$\gcd(l,2(l-i))$

(1)若$l$为奇数,$\gcd(l,2(l-i))=\gcd(l,l-i)<l$,显然矛盾

(2)若$l$为偶数,$\gcd(l,2(l-i))$在$i=\frac{l}{2}$时也是$l$,且显然此时也必然是回文的,因此恰好一个

根据性质2,我们考虑前面枚举回文的$a_{i}$来统计的方式,假设$a_{i}$最小正周期为$l$,则对于奇数的$l$其能提供$l$个不同的$a_{i}$(指最终的结果),对于偶数的$l$能提供$\frac{l}{2}$个$a_{i}$

问题即变为统计最小正周期为$l$的$a_{i}$个数,记为$f_{l}$,考虑如何计算:

性质1的逆命题也成立,即对于长为$n$且最小正周期为$l$的$a_{i}$,若$a_{[0,l)}$为回文,则$a_{i}$本身也是回文的

首先,长为$l$的回文的串一共有$k^{\lceil\frac{l}{2}\rceil}$个,接下来考虑减去最小正周期更小的$l$,也就是$\sum_{d|l,d<l}f_{d}$,显然最终所有状态都会是$n$的约数,转移复杂度即为$\sigma_{0}(n)^{2}$

当$n\le 10^{9}$,则$\sigma_{0}(n)\le 1344$(在$n=735134400$时取到),暴力dp即可

最终答案根据之前的性质2,也就是$\sum_{l|n,l为奇数}l\times f_{l}+\sum_{l|n,l为偶数}\frac{l}{2}\times f_{l}$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 3005
 4 #define mod 1000000007
 5 int n,k,ans,a[N],f[N];
 6 int pow(int n,int m){
 7     int s=n,ans=1;
 8     while (m){
 9         if (m&1)ans=1LL*ans*s%mod;
10         s=1LL*s*s%mod;
11         m>>=1;
12     }
13     return ans;
14 }
15 int main(){
16     scanf("%d%d",&n,&k);
17     for(int i=1;i*i<=n;i++)
18         if (n%i==0)a[++a[0]]=i;
19     int m=a[0];
20     for(int i=1;i<=m;i++)a[++a[0]]=n/a[m-i+1];
21     for(int i=1;i<=a[0];i++){
22         f[i]=pow(k,(a[i]+1)/2);
23         for(int j=1;j<i;j++)
24             if (a[i]%a[j]==0)f[i]=(f[i]+mod-f[j])%mod;
25     }
26     for(int i=1;i<=a[0];i++)
27         if (a[i]&1)ans=(ans+1LL*a[i]*f[i])%mod;
28         else ans=(ans+1LL*a[i]/2*f[i])%mod;
29     printf("%d",ans);
30 }
View Code

 

posted @ 2021-03-03 10:38  PYWBKTDA  阅读(84)  评论(0编辑  收藏  举报