• 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, nle 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 imes 2)的,于是写出初始矩阵(egin{bmatrix}0 & 2p end{bmatrix}),要转移到(egin{bmatrix}2p & 3p^2+2pend{bmatrix})。发现矩阵的系数有变化,无法转移。于是我们就需要添加一格来辅助转移。观察两矩阵的系数变化,我们就不难推出辅助的那个应该填什么:(egin{bmatrix}0&p&2pend{bmatrix} o egin{bmatrix}2p&p^2&3p^2+2pend{bmatrix})。于是得出中间矩阵是(egin{bmatrix}1&0&0\0&p&p\1&0&pend{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;
    }
    
  • 相关阅读:
    每日总结
    每日总结
    每日总结
    10.30
    10.29
    10.28
    10.27
    10.26
    10.25
    10.24
  • 原文地址:https://www.cnblogs.com/pfypfy/p/9084836.html
Copyright © 2020-2023  润新知