HDU6942. CCPC Strings
題意:長度為\(n\)的只含有"C"或"P"的字符串共有\(2^n\)個,問:這所有\(2^n\)個字符串中含有多少個"CCPC"(每一個"CCPC"之間不能相互重疊,即"CCPCCPC"中只能算\(1\)個"CCPC")
分析:
假設所有長度為\(n\)的"CP"字符串中互不重疊的"CCPC"的個數為\(a_n\)
若認為可以相互重疊,可以通過計算貢獻的方式進行計算
// 1. CCPC***...*****(只關注子串[1...4]的貢獻)
// 2. *CCPC**...*****(只關注子串[2...5]的貢獻)
// 3. **CCPC*...*****(只關注子串[3...6]的貢獻)
// 4. ***CCPC...*****(只關注子串[4...7]的貢獻)
// 5. ****CCP...*****(只關注子串[5...8]的貢獻)
// 6. *****CC...*****(只關注子串[6...9]的貢獻)
// .
// .
// .
//n-4. *******...CCPC*(只關注子串[n-4...n-1]的貢獻)
//n-3. *******...*CCPC(只關注子串[n-3...n]的貢獻)
"CCPC"有\((n-3)\)種擺法,剩下\((n-4)\)個字符隨便選
答案即為\((n-3)\cdot2^{n-4}\)
然而,題目要求每一個"CCPC"之間不能相互重疊
可以發現
\(1,4\)發生重疊,\(2,5\)發生重疊,\(3,6\)發生重疊,...
和上面的計算方法一樣
即"CCPCCPC"有\((n-6)\)種擺法,剩下\((n-7)\)個字符隨便選
總共為\((n-6)\cdot 2^{n-7}\)
減掉這些,發現減多了
減多了哪些?
\(1,4,7\)發生重疊,\(2,5,8\)發生重疊,\(3,6,9\)發生重疊,...
即"CCPCCPCCPC"有\((n-9)\)種擺法,剩下\((n-10)\)個字符隨便選
總共為\((n-9)\cdot 2^{n-10}\)
加上這些,發現加多了
加多了哪些?
……
以此類推,容斥原理
答案為\(a_{n}=\sum\limits_{i=1}^{\lfloor \frac{n}{3}\rfloor}(-1)^{i-1}\cdot(n-3i)\cdot 2^{n-3i-1}\)
從而有這個
所以zyf大佬送給我的遞推式\(a_n=(n-3)\cdot2^{n-4}-a_{n-3}\)是對的(干得漂亮)
然而這題到這還沒完,題目條件\(1\leq n \leq 10^9\),線性遞推搞不定
啊這,夢回高中
由於
有
令\(\frac{a_n}{2^{n-1}}=b_n\),有
令\(b_n-\frac{1}{9}n+\frac{8}{27}=c_n\),有
由\(a_1=a_2=a_3=0\)及\(c_n=\frac{a_n}{2^{n-1}}-\frac{1}{9}n+\frac{8}{27}\)
所以
由\(a_n=2^{n-1}(c_n+\frac{1}{9}n-\frac{8}{27})\)
代碼:
#include <cstdio>
typedef long long Lint;
const Lint mod = 1e9 + 7;
Lint fpow(Lint a, Lint n) {
Lint res = 1;
for (; n; n >>= 1) {
if (n & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
Lint minv(Lint a) { return fpow(a, mod - 2); }
Lint ainv(Lint a) { return mod - a; }
Lint mod_add(Lint a, Lint b) { return (a + b) % mod; }
Lint mod_mul(Lint a, Lint b) { return a * b % mod; }
Lint kn1n(Lint k, Lint n) { return n % 2 ? ainv(k) : k; }
const Lint inv1 = minv(54);
const Lint inv2 = minv(27);
const Lint inv3 = mod_mul(2, inv2);
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
int r = n % 3, k = n / 3;
Lint res = 0;
if (r == 0) {
res = mod_mul(inv1, mod_add(kn1n(8, k), mod_mul(mod_add(mod_mul(9, k), ainv(8)), fpow(8, k))));
} else if (r == 1) {
res = mod_mul(inv2, mod_add(kn1n(5, k), mod_mul(mod_add(mod_mul(9, k), ainv(5)), fpow(8, k))));
} else {
res = mod_mul(inv3, mod_add(kn1n(2, k), mod_mul(mod_add(mod_mul(9, k), ainv(2)), fpow(8, k))));
}
printf("%lld\n", res);
}
return 0;
}