P12011 【MX-X10-T7】[LSOT-4] 春开,意遥遥。
Genius_Star · · 题解
思路:
题意看起来很抽象啊,先考虑求整体的答案。
考虑给这个新定义转化一下:
发现右边就是左边两两乘积组合出来的,于是右边的数的和是
于是想到一个对
然后来考虑原来相等的定义
你展开后发现还是原来一样的:
那么考虑固定的
若两组
那么显然,若
这种底数不相同的不好处理,你考虑找一个
即:
方便设
于是选最多不同的权值的
但是你发现
于是根据阶的性质,你发现有:
那么(阶的相关证明可以看 this):
于是:
这里令
你依次考虑每个质因子的贡献,显然上式子也等于:
于是问题转化为给定序列
需要注意一下,若当前右端点扫到的
还有提一下怎么快速算一个数的阶:
因为
\delta_p(x) \mid (p - 1) ,且所有满足x^a \equiv 1 的a 都是\delta_p(x) 的倍数;于是可以考虑倒着从now = p - 1 开始,依次考虑每个质因子v ,判断\frac{now}{v} 是否满足,不满足就扔掉now \gets \frac{now}{v} ,否则保留。需要先根号的质因数分解,然后单次查询是
\log^2 p 的。
最后特判
首先一个区间至少有一个答案
b = 1 ;考虑(1, 0)^2 = (0, 1), (0, 1)^2 = (0, 1), (1, 1)^2 = (0, 0)^2 = (0, 0) ;所以若区间内包含(1, 0) 且全是(0, 1) 和(1, 0) 那么b = 2 也是合法的(注意这里是没有映射的)。
最后总复杂度应该是
顺便拿下最优解。
完整代码:
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#define lowbit(x) x & (-x)
#define pi pair<ll, ll>
#define ls(k) k << 1
#define rs(k) k << 1 | 1
#define fi first
#define se second
using namespace std;
using namespace __gnu_pbds;
typedef __int128 __;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
const int N = 1e5 + 10, mod = 1e9 + 7;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
ll p;
int n, ans, cnt, sum;
int num[N];
ll h[N], pri[N], x[N], y[N], A[N];
bool vis[N];
inline ll qpow(ll a, ll b){
ll ans = 1;
while(b){
if(b & 1)
ans = (__) ans * a % p;
a = (__) a * a % p;
b >>= 1;
}
return ans;
}
inline void init(ll n){
for(ll i = 2; i * i <= n; ++i){
if(n % i == 0){
pri[++cnt] = i;
while(n % i == 0){
++num[cnt];
n /= i;
}
}
}
if(n > 1){
pri[++cnt] = n;
num[cnt] = 1;
}
}
inline ll ask(ll x){
ll now = p - 1;
for(int i = 1; i <= cnt; ++i){
for(int j = 1; j <= num[i]; ++j){
if(qpow(x, now / pri[i]) == 1)
now /= pri[i];
else
break;
}
}
return now;
}
int main(){
n = read(), p = read();
if(p == 2){
ans = (1ll * n * (n + 1) >> 1) % mod;
int pre = 0, lst = 0;
for(int i = 1; i <= n; ++i){
int x = read(), y = read();
if(x && !y)
lst = i;
if(x == y)
pre = i;
ans = (ans + max(lst - pre, 0)) % mod;
}
write(ans);
putchar('\n');
return 0;
}
init(p - 1);
for(int i = 1; i <= n; ++i){
ll a = read(), b = read();
x[i] = (a + b) % p;
y[i] = (b - a + p) % p;
if(!x[i] || !y[i])
vis[i] = 1;
else
A[i] = ask((__)x[i] * qpow(y[i], p - 2) % p);
}
// for(int i = 1; i <= n; ++i)
// cerr << A[i] << ' ';
// cerr << '\n';
for(int r = 1; r <= n; ++r){
if(vis[r])
sum = r;
else{
h[r] = A[r];
for(int l = r - 1; l >= 1; --l){
if(vis[l])
break;
ll t = __gcd(h[l], A[r]);
if(t == A[r])
break;
sum = (sum - h[l] % mod + mod) % mod;
h[l] = h[l] / t * A[r];
sum = (sum + h[l] % mod + mod) % mod;
}
sum = (sum + h[r] % mod) % mod;
}
ans = (ans + sum) % mod;
}
// for(int l = 1; l <= n; ++l){
// ll now = 0;
// for(int r = l; r <= n; ++r){
// if(vis[r]){
// ans = (ans + (n - r + 1)) % mod;
// break;
// }
// if(!now)
// now = A[r];
// else
// now = now / __gcd(now, A[r]) * A[r];
// ans = (ans + now % mod) % mod;
// }
// }
write(ans);
return 0;
}