http://codeforces.com/contest/185/problem/D
题意: 求LCM(k^(2^l)+1, k^(2^(l+1)) + 1, k^(2^(l+2)) + 1, ... , k^(2^r) + 1) mod p. l, r都很大,不能直接求。
思路:假设x=k^(2^l)+1,那么k^(2^(l+1))+1 = (x-1)^2+1 = x^2-2^x+2, 而gcd(x, x^2-2^x+1)=gcd(x, 2),所以gcd(k^(2^l)+1, k^(2^(l+1)) + 1)要么为1,要么为2。显然就是k的奇偶问题。知道了GCD,LCM就好求了。总的来说,结果大致可以归结为:
1.若k是奇数,答案就是(k^(2^l)+1)(k^(2^(l+1)) + 1)...(k^(2^r)+1)/2^(r - l)
2.若k是偶数,答案就是(k^(2^l)+1)(k^(2^(l+1)) + 1)...(k^(2^r)+1)
第二个关键在于怎么求(k^(2^l)+1)(k^(2^(l+1)) + 1)...(k^(2^r)+1)
其实把这条式化开整理一下:(k^(2^l)+1)(k^(2^(l+1)) + 1)...(k^(2^r)+1) = 1 + k^(2^l) + k^(2*(2^l)) + k^(2^(3*(2^l))) + ... + k^(2^((2^(r-l+1)-1)*(2^l)))
=右边就是一个等比公式,直接用公式代进去就可以了
公式有除法运算,求余的话要注意有可能跟p不是互素,不过很容易想到当且仅当p|(k^(2^l)-1)是才出现这种情况,特殊处理一下就行了。
最后如果k是奇数在除以一下2^(r-l)即可。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define sqr(x) ((x) * (x))
#define two(x) (1 << (x))
#define ord(x, y, z) ((x) <= (y) && (y) <= (z))
#define X first
#define Y second
typedef long long LL;
typedef pair<int, int> pair2;
const int N = 1;
const double eps = 1e-9;
const int oo = 1000000000;
int k, p;
LL l, r;
int pow2(int x, LL y, int p) {
if (y == 0) {
return 1 % p;
} else if (y == 1) {
return x % p;
} else {
int t = pow2(x, y >> 1, p);
t = (LL)t * t % p;
if (y & 1) {
return (LL)t * x % p;
} else {
return t;
}
}
}
int sum(LL x) {
return (LL)(pow2(k, pow2(2, x + 1, p - 1), p) - 1) * pow2(k - 1, p - 2, p) % p;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
cin >> k >> l >> r >> p;
int a = 1;
if (k % p) {
a = pow2(2, r - l + 1, p) % p;
if (pow2(k, pow2(2, l, p - 1), p) != 1) {
a = (LL)sum(r) * pow2(sum(l - 1), p - 2, p) % p;
}
}
if (k & 1) {
a = (LL)a * pow2(pow2(2, r - l, p), p - 2, p) % p;
}
a = (a + p) % p;
printf("%d\n", a);
}
return 0;
}
半年没写题解了……有空的时候上去吹吹也不错,哈哈。