20180524模拟赛T3——Word

【题目描述】

有一个星球要创造新的单词,单词有一些条件:

  1. 字母集有\(p\)个元音和\(q\)个辅音,单词由字母构成
  2. 每个单词最多有\(n\)个元音和\(n\)个辅音(同一元音或辅音可重复使用)
  3. 每个单词中元音总是出现在所有辅音之前,可以没有元音或没有辅音
  4. 每个单词至少有一个字母
  5. 可以在字母上标记重音。元音中最多标记一个,辅音中也最多标记一个,一个单词中最多标记两个字母为重音
  6. 如果两个单词字母、字母顺序或者重音不同就认为这两个单词不同。

他们想要知道一共能创造多少不同的单词,由于答案可能很大,所以只要输出答案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;
}

猜你喜欢

转载自www.cnblogs.com/pfypfy/p/9084836.html