20180524模拟赛T3——Word
【题目描述】
有一个星球要创造新的单词,单词有一些条件:
- 字母集有\(p\)个元音和\(q\)个辅音,单词由字母构成
- 每个单词最多有\(n\)个元音和\(n\)个辅音(同一元音或辅音可重复使用)
- 每个单词中元音总是出现在所有辅音之前,可以没有元音或没有辅音
- 每个单词至少有一个字母
- 可以在字母上标记重音。元音中最多标记一个,辅音中也最多标记一个,一个单词中最多标记两个字母为重音
- 如果两个单词字母、字母顺序或者重音不同就认为这两个单词不同。
他们想要知道一共能创造多少不同的单词,由于答案可能很大,所以只要输出答案mod M后的值。
【输入格式】
输入文件word.in包含4个正整数\(p,q,n,M\)
【输出格式】
输出文件word.out包含一个非负整数表示能创造出的新单词数 mod M 后的值。
【样例输入1】
1 1 1 9
【样例输出1】
8
【样例输入2】
2 3 2 1000
【样例输出2】
577
【样例输入3】
1 1 1000000000 1000000000
【样例输出3】
0
【数据规模】
对于 \(30\%\)的数据,\(p, q, n\le 7\)
对于\(60\%\)的数据,\(n \le 100000\)
对于\(100\%\)的数据,$ p, q, n, M ≤ 10^9$
题解
个人认为这题的题目描述可能会造成一点小小的误解。那就是“所有”的元音都应该放在辅音之前,即元辅音可以分开来看。
那我们就只看元音吧。
于是我们就可以很自然地推出\(ans=\sum_{i=1}^n(i+1)p^i\)。由于有一个叫重音的东西,所以系数是\(i+1\)。直接算会T(70分),于是我们就想到了矩阵快速幂(orz严公分块、倍增)。
首先我们当然想到是推\(2\times 2\)的,于是写出初始矩阵\(\begin{bmatrix}0 & 2p \end{bmatrix}\),要转移到\(\begin{bmatrix}2p & 3p^2+2p\end{bmatrix}\)。发现矩阵的系数有变化,无法转移。于是我们就需要添加一格来辅助转移。观察两矩阵的系数变化,我们就不难推出辅助的那个应该填什么:\(\begin{bmatrix}0&p&2p\end{bmatrix}\to \begin{bmatrix}2p&p^2&3p^2+2p\end{bmatrix}\)。于是得出中间矩阵是\(\begin{bmatrix}1&0&0\\0&p&p\\1&0&p\end{bmatrix}\)话说个人这题的矩阵的推法挺精妙的,建议仔细回味一下)。
然后就用同样的方法算辅音即可。
代码
#include <cstring>
#include <cmath>
#include <fstream>
using namespace std;
typedef long long LL;
ifstream fin("word.in");
ofstream fout("word.out");
LL chen[4][4], q, p, n, mod, jg[2][4], tt[4][4];
inline void pow(int aa)
{
while(aa)
{
if(aa & 1)
{
for(int j = 1; j <= 3; ++j)
{
tt[1][j] = 0;
for(int k = 1; k <= 3; ++k)
tt[1][j] = (tt[1][j] + jg[1][k] * chen[k][j] % mod) %mod;
}
memcpy(jg, tt, sizeof(jg));
}
aa >>= 1;
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j)
{
tt[i][j] = 0;
for(int k = 1; k <= 3; ++k)
tt[i][j] = (tt[i][j]+chen[i][k]*chen[k][j]%mod)%mod;
}
memcpy(chen, tt, sizeof(chen));
}
}
int main()
{
fin >> q >> p >> n >> mod;
jg[1][1] = (q<<1) % mod;
jg[1][2] = q % mod;
chen[1][1] = chen[2][1] = chen[2][2] = q % mod;
chen[1][3] = chen[3][3] = 1;
pow(n);
LL sumy = jg[1][3];
memset(jg, 0, sizeof(jg));
memset(chen, 0, sizeof(chen));
jg[1][1] = (p<<1) % mod;
jg[1][2] = p%mod;
chen[1][1] = chen[2][1] = chen[2][2] = p % mod;
chen[1][3] = chen[3][3] = 1;
pow(n);
LL sumf = jg[1][3];
LL ans = (sumy*sumf%mod + sumy + sumf) % mod;
fout << ans;
return 0;
}