循环节其实就可以看做取模,一般的1e9 + 7其实就是个循环节,只是大了点……
切入正题 HDU4291
- g(x)很明显的矩阵快速幂
- 本地直接暴力找循环节
ll a = 0, b = 1; for(int i = 2; ; ++i){ printf("%d ", i); a = (3 * b + a) % MOD; //swap(a, b); 位运算更快 a = a ^ b; b = a ^ b; a = a ^ b; if(a == 0 && b == 1) printf("Mod= %d\n", i); }
一定要 开 long long !!!
我没开 long long 卡了一个多小时呜呜呜呜呜 - 三个g嵌套,就分了三个循环节
我最开始没有把循环节的概念弄清楚,写成了这样
n = quickpoww(n % Mod3).m[0][1];//g(g(g(x)))的循环节为 MOD3
n = quickpoww(n % Mod2).m[0][1];//g(g(x)) 的循环节为 MOD2
n = quickpoww(n % Mod1).m[0][1];//g(x)的循环节为MOD1
在得到循环节的情况下快速幂直接对1e9+7取模
自然就……
其实仔细一想,对变量取模就是利用了当前函数的循环节,而对于当前函数对外面一层的函数(嵌套情况下)的循环节则是对函数值(此时已是作为变量)取模。
例如,对于g(g(g(x))),x的循环节为240,而x对240取模后算出的g(x)在函数g(g(g(x)))中的循环节则是183120,即第二层取模应取183120。至于1e9+7,它只不过是最外面一层函数的循环节
while(scanf("%lld", &n) != EOF){
n = quickpoww(n % Mod3, Mod2).m[0][1];//g(g(g(x)))的循环节为 MOD3
n = quickpoww(n % Mod2, Mod1).m[0][1];//g(g(x)) 的循环节为 MOD2
n = quickpoww(n % Mod1, Mod0).m[0][1];//g(x)的循环节为MOD1
printf("%lld\n", n);
}
其实1e9+7也不过是最外面一层的循环节而已,不能当成“万能取模”随便用到快速幂里面,对于不同的循环节有不同的模值。
最后AC代码:
#include<bits/stdc++.h>
#define ll long long
#define MAXN 2
static const int Mod0 = 1000000007;
static const int Mod1 = 222222224;
static const int Mod2 = 183120;
static const int Mod3 = 240;
using namespace std;
typedef struct Matrix{
ll m[MAXN][MAXN];
}Matrix;
Matrix mat_muti(Matrix a, Matrix b, int mod){
Matrix ans;
for(int i = 0; i < MAXN; i++)
for(int j = 0; j < MAXN; j++){
ans.m[i][j] = 0;
for(int k = 0; k < MAXN; k++) ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j]) % mod;
}
return ans;
}
Matrix quickpoww(int n, int mod){
Matrix ans, base;
ans.m[0][0] = 1; ans.m[0][1] = ans.m[1][0] = ans.m[1][1] = 0;
base.m[0][0] = 3; base.m[1][1] = 0; base.m[1][0] = base.m[0][1] = 1;
while(n > 0){
if(n & 1) ans = mat_muti(ans, base, mod);
base = mat_muti(base, base, mod);
n >>= 1;
}
return ans;
}
int main(){
ll n;
while(scanf("%lld", &n) != EOF){
n = quickpoww(n % Mod3, Mod2).m[0][1];//g(g(g(x)))的循环节为 MOD3
n = quickpoww(n % Mod2, Mod1).m[0][1];//g(g(x)) 的循环节为 MOD2
n = quickpoww(n % Mod1, Mod0).m[0][1];//g(x)的循环节为MOD1
printf("%lld\n", n);
}
return 0;
}