求长度不超过n的双回文串个数。
n ≤ 1 0 9 n\leq 10^9 n≤109
这是个结论题,主要难点是分析出弱回文串的结构。(或者打表发现他)
弱双回文串=第一个回文串可为空的双回文串。
最小弱回文指的是,最小整周期为n的长度为n的弱回文串。
对拍,上述结论均正确,开始你的数论表演:
设:
f ( n ) f(n) f(n)为长度为n的最小弱双回文串个数,
g ( n ) g(n) g(n)为长度为n的弱双回文划分个数,
h ( n ) h(n) h(n)为长度为n的弱双回文个数。
g ( n ) g(n) g(n)只需分类讨论一下奇偶,可得
g ( n ) = { n C ( n + 1 ) / 2 , n % 2 = 1 n / 2 ( C n / 2 + C n / 2 + 1 ) , n % 2 = 0 g(n)=\begin{cases} nC^{(n+1)/2},n\%2=1\\n/2(C^{n/2}+C^{n/2+1}),n\%2=0 \end{cases} g(n)={nC(n+1)/2,n%2=1n/2(Cn/2+Cn/2+1),n%2=0
由上述, g ( n ) = ∑ d ∣ n f ( d ) × ( n / d ) g(n)=\sum_{d|n}f(d)\times (n/d) g(n)=d∣n∑f(d)×(n/d),反演得 f ( n ) = ∑ d ∣ n g ( d ) ( n / d ) μ ( n / d ) f(n)=\sum_{d|n}g(d)(n/d)\mu(n/d) f(n)=d∣n∑g(d)(n/d)μ(n/d)
并且有 h ( n ) = ∑ d ∣ n f ( d ) h(n)=\sum_{d|n}f(d) h(n)=d∣n∑f(d)
接下来是求解 ∑ i = 1 n h ( n ) \sum_{i=1}^{n}h(n) ∑i=1nh(n)
= ∑ i = 1 n ∑ d ∣ i f ( d ) =\sum_{i=1}^{n}\sum_{d|i}f(d) =i=1∑nd∣i∑f(d)
= ∑ d = 1 n f ( d ) ( n / d ) =\sum_{d=1}^{n}f(d)(n/d) =d=1∑nf(d)(n/d)
= ∑ d = 1 n ( n / d ) ∑ k ∣ d g ( k ) ( d / k ) μ ( d / k ) =\sum_{d=1}^{n}(n/d)\sum_{k|d}g(k)(d/k)\mu(d/k) =d=1∑n(n/d)k∣d∑g(k)(d/k)μ(d/k)
= ∑ k = 1 n g ( k ) ∑ d ′ = 1 n / k ( n / k d ′ ) μ ( d ′ ) d ′ =\sum_{k=1}^{n}g(k)\sum_{d'=1}^{n/k}(\frac {n/k} {d'})\mu(d')d' =k=1∑ng(k)d′=1∑n/k(d′n/k)μ(d′)d′
该式可以分块, g g g是个等差比可以快速求和。现在要快速算后面的关于n/k的函数。
T ( n ) = ∑ i = 1 n ( n i ) μ ( i ) i T(n)=\sum_{i=1}^{n}(\frac {n} {i})\mu(i)i T(n)=i=1∑n(in)μ(i)i,注意括号里是下取整。
= ∑ j = 1 n ∑ d ∣ j μ ( d ) d =\sum_{j=1}^{n}\sum_{d|j}\mu(d)d =j=1∑nd∣j∑μ(d)d,这是个积性函数前缀和,直接min25即可。(也可以杜教筛)
接下来计算最小回文数,基本同理:
设 b ( n ) b(n) b(n)为长度为n的回文数, c ( n ) c(n) c(n)为长度为n的最小回文。注意到 b ( n ) b(n) b(n)很好算。
b ( n ) = ∑ d ∣ n c ( d ) b(n)=\sum_{d|n}c(d) b(n)=d∣n∑c(d)
反演, c ( n ) = ∑ d ∣ n b ( d ) μ ( n / d ) c(n)=\sum_{d|n}b(d)\mu(n/d) c(n)=d∣n∑b(d)μ(n/d)
对 c ( n ) c(n) c(n)求前缀和 ∑ i = 1 n c ( i ) \sum_{i=1}^{n} c(i) i=1∑nc(i)
= ∑ i = 1 n ∑ d ∣ i b ( d ) μ ( i / d ) =\sum_{i=1}^{n} \sum_{d|i}b(d)\mu(i/d) =i=1∑nd∣i∑b(d)μ(i/d)
= ∑ d = 1 n b ( d ) ∑ i = 1 n / d μ ( i ) =\sum_{d=1}^n b(d)\sum_{i=1}^{n/d}\mu(i) =d=1∑nb(d)i=1∑n/dμ(i)
分块+min25/杜教筛即可。
(由于我的脑抽,以下弱回文=弱双回文
接下来是对结论的证明,学艺不精可能有伪证。。。请各位抱着批判的眼光看待。。。
首先有弱周期引理:若有周期 p , q p,q p,q且 p + q ≤ ∣ S ∣ p+q\leq |S| p+q≤∣S∣,则 g c d ( p , q ) gcd(p,q) gcd(p,q)为S的一个周期。
一个有两个以上划分的弱回文是整周期串。
只需找出两个周期 a , b a,b a,b使得 g c d ( a , b ) ∣ s gcd(a,b)|s gcd(a,b)∣s。设两个划分的第一个回文长度差值为 t t t,容易发现s同时有 t t t的周期和border.
t的周期:大回文前缀包含小回文前缀,会产生长度为他们的差的周期。
t的border:通过一些回文翻转即可发现。
弱回文串 S S S的最小整周期是最小弱回文串,并且该串的弱回文划分数恰好为 ∣ S ∣ / 最 小 整 周 期 |S|/最小整周期 ∣S∣/最小整周期。
设某个弱回文串的最小整周期所对应的串为 T T T,由 L e m m a 2 Lemma 2 Lemma2,T至多只有一个弱回文划分。
下面证明 T T T存在一个弱回文划分。
当 T = S T=S T=S时引理成立,否则设串 S = p q S=pq S=pq为其弱回文划分,取包含至少一个T的部分,不失一般性地我们取 q q q, q q q是若干个T与一个T的可空前缀拼接而成。由于q是回文串,容易发现该前缀是回文串。并且去掉该前缀之后剩下的 T ′ T' T′也是回文串。这就证明了 T T T是一个最小弱回文串(只存在唯一划分)。
然后考虑其弱回文划分数。首先至少存在 ∣ S ∣ / ∣ T ∣ |S|/|T| ∣S∣/∣T∣个。然后,由上述分析我们回文划分的分界点必须取在 T T T的回文划分分界点上,否则会与 T T T只存在唯一划分矛盾。
#include
using namespace std;
typedef long long ll;
const int mo = 1e9 + 7, N = 1e6 + 10;
int n, c;
int is[N], mu[N];
ll p[N];
int loc[N], loc2[N], w[N], B, precnt[N], presum[N], preT[N];
#define id(x) ((x) <= B ? loc[x] : loc2[n / (x)])
void init(int n) {
mu[1] = 1;
for(int i = 2; i <= n; i++) {
if (!is[i]) p[++*p] = i, mu[i] = -1;
for(int j = 1; p[j] * i <= n; j++) {
is[p[j] * i] = 1;
if (i % p[j] == 0) {
break;
} else {
mu[i * p[j]] = -mu[i];
}
}
precnt[i] = precnt[i - 1] + (is[i] == 0 ? 1 : 0);
presum[i] = (presum[i - 1] + (is[i] == 0 ? i : 0)) % mo;
preT[i] = (preT[i - 1] + (is[i] == 0 ? 1 - i : 0)) % mo;
}
}
ll cnt[N], sum[N], smu[N], aT[N];
void min25() {
B = sqrt(n);
for(int i = 1; i <= n; ) {
int v = n / i, r = n / v;
w[++(*w)] = n / i;
if (v <= B) loc[v] = *w; else loc2[i] = *w;
cnt[*w] = v - 1;
sum[*w] = (2ll + v) * (v - 1) / 2 % mo;
i = r + 1;
}
for(int i = 1; p[i] * p[i] <= n; i++) {
for(int j = 1; w[j] >= p[i] * p[i]; j++) {
cnt[j] -= cnt[id(w[j] / p[i])] - precnt[p[i] - 1];
sum[j] = (sum[j] - p[i] * (sum[id(w[j] / p[i])] - presum[p[i] - 1])) % mo;
}
}
for(int i = 1; i <= *w; i++) {
smu[i] = -cnt[i];
aT[i] = cnt[i] - sum[i];
}
for(int i = p[0]; i; i--) {
for(int j = 1; w[j] >= p[i] * p[i]; j++) {
for(int e = 1, b = p[i]; b * p[i] <= w[j]; e++, b *= p[i]) {
if (e == 1)
smu[j] = (smu[j] + (-1) * (smu[id(w[j] / b)] - (-1) * precnt[p[i]]));
aT[j] = (aT[j] + (1 - p[i]) * (aT[id(w[j] / b)] - preT[p[i]]) + (1 - p[i])) % mo;
}
}
}
}
ll ans;
ll ksm(ll x, ll y) {
ll ret = 1; for(; y; y >>= 1) {
if (y & 1) ret = ret * x % mo;
x = x * x % mo;
}
return ret;
}
ll g(ll n) {
if (n & 1) return n * ksm(c, (n + 1) / 2);
else return n / 2 * (ksm(c, n >> 1) + ksm(c, (n >> 1) + 1)) % mo;
}
ll A1, B1, A2, B2;
ll _sumg(ll n) {
ll p1 = ksm(c, n / 2 + 1) * (A1 * (n / 2) % mo + B1) - c * B1;//odd
p1 %= mo;
ll dt = 0;
ll p2 = ksm(c, n / 2 + 1) * (A2 * (n / 2) % mo + B2) - c * B2; //even1
p2 %= mo;
p2 = p2 * (1 + c) % mo; //even2
return (p1 + p2) % mo;
}
ll sumg(ll n) {
ll rv = _sumg(n - (n & 1)) + ((n & 1) ? g(n) : 0);
return rv % mo;
}
ll b(ll n) {
return ksm(c, (n + 1) >> 1);
}
ll _sumb(ll n) {
ll cnt = n >> 1;
return 2 * (ksm(c, cnt + 1) - c) % mo * ksm(c - 1, mo - 2) % mo;
}
ll sumb(ll n) {
//ll ret = 0;
ll rv = _sumb(n - (n & 1)) + (n & 1 ? b(n) : 0);
//for(int i = 1; i <= n; i++) ret = (ret + b(i)) % mo;
//assert((ret + mo) % mo == (rv + mo) % mo);
return rv;
}
ll sumu(ll x) {
return smu[id(x)] + 1;
}
ll T(ll x) {
return aT[id(x)] + 1;
}
int main() {
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
cin >> n >> c; init(1e6); min25();
A1 = 2 * ksm(c - 1, mo - 2) % mo;
B1 = - (1 + A1) * ksm(c - 1, mo - 2) % mo;
A2 = 1 * ksm(c - 1, mo - 2);
B2 = - A2 * ksm(c - 1, mo - 2) % mo;
for(int l = 1; l <= n; ) {
int r = n / (n / l);
ans = (ans + (sumg(r) - sumg(l - 1)) * T(n / l)) % mo;
ans = (ans - (sumb(r) - sumb(l - 1)) * sumu(n / l)) % mo;
l = r + 1;
}
cout << (ans + mo) % mo << endl;
}