20230201 模拟赛改题

T1 课后练习题

简要题意:求方程 \(x^k\equiv n\ (\bmod\ x + 1)\) 的解的个数,\(1\le n,k\le 10^{14}\)

可以尝试找规律:

\(k=1\) 时:

\[x\equiv n\ (\operatorname{mod}\ x+1)\\ x+m(x+1)=n\\ x+mx+m=n\\ x(m+1)+m=n\\ x(m+1)+(m+1)=n+1\\ (x+1)(m+1)=n+1 \]

答案就是 \(n+1\) 的约数个数 \(-1\)

\(k=2\) 时:

\[x^2\equiv n\ (\operatorname{mod}\ x+1)\\ x(x+1)-x\equiv n\ (\operatorname{mod} \ x+ 1)\\ -x\equiv n\ (\operatorname{mod}\ x+1) \]

剩下的与 \(k=1\) 时的做法类似,只不过答案变成了 \(n-1\) 的约数个数 \(-1\)

\(k=3\) 时:

\[x^3\equiv n\ (\operatorname{mod}\ x+1)\\ x^2(x+1)-x^2\equiv n\ (\operatorname{mod} \ x+ 1)\\ -x^2\equiv n\ (\operatorname{mod}\ x+1) \]

剩下的与 \(k=2\) 时的做法类似,只不过答案变成了 \(n+1\) 的约数个数 \(-1\)

总结出规律:当 \(k\) 为奇数时,答案是 \(n+1\) 的约数个数 \(-1\),否则答案是 \(n-1\) 的约数个数 \(-1\)

code:

#include<iostream>
using namespace std;
int main() {
    long long n, k, ans = 0;
    scanf("%lld%lld", &n, &k);
    if(k & 1) n++;
    else n--;
    for(long long i = 1; i * i <= n; i++) {
   	if(n % i == 0) {
            if(n / i == i) ans++;
            else ans += 2;
	}
    }
    printf("%lld", ans - 1);
    return 0;
} 

T2 拼图

求用无数个 \(2\times 2\)\(1\times 4\) 的拼图拼出一块 \(4\times n\) 的拼图的方案数,\(n\le 10^{18}\)

首先公布结论:\(dp_i=dp_{i-1}+dp_{i-2}+5\times dp_{i-4}-dp_{i-5}+dp_{i-6}-dp_{i-8}\)

接下来我来证明这个式子:

考虑上一个位置的拼图的情况,无非就 \(3\) 种,列举在下图:

Case 1:

情况 a 最简单,方案数就是 \(dp_{i-1}\)

接下来考虑 Case 1 的情况 b:

无非也是 \(3\) 种情况,列举在下图:

Case 2:

那么我们考虑 Case 2 的情况 a:答案就是 \(dp_{i-4}\)

接下来考虑情况 b:

我们令 \(x_i\) 表示这种情况中从 \(1\) 到第 \(i\) 个位置对总答案的贡献,这次只有两种情况,列举在下图:

Case 3:

考虑 Case 3 的情况 a:答案就是 \(dp_{i-4}\)

考虑 Case 3 的情况 b,这种情况的答案就是 \(x_{i-4}\)

所以 \(x_i=dp_{i-4}+x_{i-4}\)

接下来考虑 Case 2 中的情况 c,我们令 \(y_i\) 表示这种情况中从 \(1\) 到第 \(i\) 个位置对总答案的贡献,此时有 \(2\) 种情况:

Case 4:

考虑 Case 4 中的情况 a,显然,答案为 \(dp_{i-4}\)

接下来考虑 Case 4 中的情况 b,此时答案为 \(y_{i-2}\)

所以 \(y_i=dp_{i-4}+y_{i-2}\)

此时 Case 1 中情况 b 的答案就是:

\[\begin{aligned} dp_{i-4}+x_i+y_i&=dp_{i-4}+(dp_{i-4}+x_{i-4})+(dp_{i-4}+y_{i-2})\\ &=3\times dp_{i-4}+x_{i-4}+y_{i-2}\\ &=3\times dp_{i-4}+x_{i-4}+dp_{i-6}+y_{i-4} \end{aligned} \]

接下来考虑 Case 1 中的情况 c,我们令 \(z_i\) 表示这种情况中从 \(1\) 到第 \(i\) 个位置对总答案的贡献,此时有 \(2\) 种情况:

Case 5:

对于 Case 5 中的情况 a,答案为 \(dp_{i-2}\)

对于 Case 5 中的情况 b,此时答案为 \(z_{i-2}\)

所以 \(z_{i}=dp_{i-2}+z_{i-2}\)

所以 Case 1 中的情况 c 的答案就是:

\[\begin{aligned} z_i&=(dp_{i-2}+z_{i-2})\\ &=dp_{i-2}+dp_{i-4}+z_{i-4} \end{aligned} \]

所以总答案就是:

\[\begin{aligned} dp_{i}&=dp_{i-1}+(dp_{i-4}+x_i+y_i)+(z_i)\\ &=dp_{i-1}+(3\times dp_{i-4}+dp_{i-6}+x_{i-4}+y_{i-4})+(dp_{i-2}+dp_{i-4}+z_{i-4})\\ &=(dp_{i-1}+dp_{i-2}+4\times dp_{i-4}+dp_{i-6})+(x_{i-4}+y_{i-4}+z_{i-4}) \end{aligned} \]

这时我们令 \(i=i-4\) 再求一遍 \(dp_{i}\)

\[\begin{aligned} dp_{i-4}&=dp_{i-5}+dp_{i-8}+x_{i-4}+y_{i-4}+z_{i-4}\\ \end{aligned} \]

所以:

\[dp_{i-4}-dp_{i-5}-dp_{i-8}=x_{i-4}+y_{i-4}+z_{i-4} \]

回到 \(dp_i\) 的式子:

\[\begin{aligned} dp_{i}&=(dp_{i-1}+dp_{i-2}+4\times dp_{i-4}+dp_{i-6})+(dp_{i-4}-dp_{i-5}-dp_{i-8})\\ &=dp_{i-1}+dp_{i-2}+5\times dp_{i-4}-dp_{i-5}+dp_{i-6}-dp_{i-8} \end{aligned} \]

证毕。

当然,只是这一个式子很明显会超时,我们还需要一些优化。

考虑用矩阵乘法优化这个过程:

首先构造初始矩阵:

\[\begin{bmatrix} dp_{n-7}&dp_{n-6}&dp_{n-5}&dp_{n-4}&dp_{n-3}&dp_{n-2}&dp_{n-1}&dp_{n} \end{bmatrix} \]

我们的目标是转移到这个矩阵:

\[\begin{bmatrix} dp_{n-6}&dp_{n-5}&dp_{n-4}&dp_{n-3}&dp_{n-2}&dp_{n-1}&dp_{n}&dp_{n+1} \end{bmatrix} \]

根据上面的递推关系,我们很容易构造出中间矩阵:

\[\begin{bmatrix} 0&0&0&0&0&0&0&-1\\ 1&0&0&0&0&0&0&0\\ 0&1&0&0&0&0&0&1\\ 0&0&1&0&0&0&0&-1\\ 0&0&0&1&0&0&0&5\\ 0&0&0&0&1&0&0&0\\ 0&0&0&0&0&1&0&1\\ 0&0&0&0&0&0&1&1 \end{bmatrix} \]

直接上矩阵快速幂就好了 qwq:

#include<iostream>
#include<cstring>
using namespace std;
const long long mod = 1e9 + 7;
const long long res[] = {1, 1, 2, 3, 9, 16, 35, 65, 143};

struct Matrix {
    int n, m;
    long long a[10][10];

    Matrix() {memset(a, 0, sizeof(a));}

    Matrix operator * (const Matrix& x) const {
    	Matrix res;
    	res.n = n, res.m = x.m;
	for(int i = 1; i <= n; i++) {
	    for(int j = 1; j <= x.m; j++) {
	    	for(int k = 1; k <= m; k++) {
	            res.a[i][j] = (res.a[i][j] + a[i][k] * x.a[k][j]) % mod;
		}
	    }
	}
	return res;
    }
} a, BASE;

void init() {
    a.n = 1, a.m = 8;
    for(int i = 1; i <= 8; i++) {
	a.a[1][i] = res[i];
    }
    BASE.n = BASE.m = 8;
    BASE.a[1][8] = -1, BASE.a[2][1] = 1;
    BASE.a[3][2] = 1, BASE.a[4][3] = 1;
    BASE.a[3][8] = 1, BASE.a[4][8] = -1;
    BASE.a[5][4] = 1, BASE.a[5][8] = 5;
    BASE.a[6][5] = 1, BASE.a[7][6] = 1;
    BASE.a[7][8] = 1, BASE.a[8][7] = 1;
    BASE.a[8][8] = 1;
}

Matrix fpow(long long b) {
    Matrix ans = a;
    while(b) {
    	if(b & 1) ans = ans * BASE;
	BASE = BASE * BASE;
	b >>= 1;
    }
    return ans;
}

int main() {
    long long n;
    scanf("%lld", &n);
    if(n <= 8) return printf("%lld", res[n]) & 0;
    init();
    printf("%lld", fpow(n - 8).a[1][8]);
    return 0;
}
posted @ 2023-02-02 23:06  lnlmz  阅读(41)  评论(1编辑  收藏  举报