子序列
合法的子序列均只有一个元素,答案显然为
数据点 5\sim 11 : O(n^2) 暴力递推。
先不考虑不合法的子序列,即
设
显然
显然
再设
那么
那么我们分别考虑这
关于
于是我们就可以
而现在我们需要考虑去掉不合法的序列。
改设
发现由上式的原理可以由
根据基本容斥原理,答案为
数据点 15\sim 17 : O(nlogn) 逆元。
根据前文中推出的式子,同理:
移项得:
同理
由于
数据点 18\sim 22 : O(nlogn) 合并区间 \& 倍增。
我们是否能由
方法与由
接下来只要利用倍增的思想,预处理出
时空复杂度都是
数据点 23\sim 25 :
正解
- 乱搞一:
仍然倍增,但空间会炸,于是我们类似分块,以
- 乱搞二:
据说有方法可以实现膜数非质数逆元,不太了解这里就不讲了,但时间复杂度仍然要
- 乱搞三:
区间合并,区间查询,显然可以线段树,时间复杂度
注意由于要同时合并
我的方法是直接用 pair<> 作函数类型,如果有其它方法欢迎评论提出。
但由于线段树巨大的常数还是有一定风险的,事实上出题人写的线段树这
- 正解:分块。
大家都知道分块一般是
因为我们要求的区间长度只有
所以我们可以以
则我们只需预处理出
Code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define G() Cr = getchar()
#define LL long long
LL Xr, Fr; char Cr;
inline LL rd() {
Xr = 0, Fr = 1, G();
while(Cr < '0' || Cr > '9') {if(Cr == '-') Fr = -1; G();}
while(Cr >= '0' && Cr <= '9') Xr = (Xr<<1) + (Xr<<3) + (Cr&15), G();
return Xr * Fr;
}
#define MAX_N 1000005
LL n, k, mod;
LL va[MAX_N], f[MAX_N][3], b[MAX_N][3], l[MAX_N], r[MAX_N], ans, s; // 0 -> from left ; 1 -> from right
LL work( LL L, LL R ) {
if( L == R ) return va[L] * va[L] % mod;
if( l[L] == l[R] ) return f[R][0];
LL x, y, A, B;
x = f[L][1], y = f[R][0];
A = b[L][1], B = b[R][0];
return ( x + y + A * y % mod + B * x % mod ) % mod;
}
int main() {
n = rd(), k = rd(), mod = rd();
for( int i = 1; i <= n; i++ ) va[i] = rd();
if(!k) {
for( int i = 1; i <= n; i++ ) ans = ( ans + va[i] * va[i] ) % mod;
cout << ans;
return 0;
}
for( int i = 1; i <= n; i++ ) l[i] = ( i - 1 ) / k * k + 1, r[i] = ( ( i - 1 ) / k + 1 ) * k;
for( int i = 1; i <= n; i++ ) {
if( i == l[i] ) b[i][0] = va[i], f[i][0] = va[i] * va[i] % mod;
else {
f[i][0] = (va[i] * va[i] % mod * ( 1 + b[i-1][0] ) % mod + f[i-1][0] * ( 1 + va[i] ) % mod ) % mod;
b[i][0] = ( b[i-1][0] * ( 1 + va[i] ) + va[i] ) % mod;
}
}
for( int i = n; i >= 1; i-- ) {
if( i == r[i] ) b[i][1] = va[i], f[i][1] = va[i] * va[i] % mod;
else {
f[i][1] = (va[i] * va[i] % mod * ( 1 + b[i+1][1] ) % mod + f[i+1][1] * ( 1 + va[i] ) % mod ) % mod;
b[i][1] = ( b[i+1][1] * ( 1 + va[i] ) + va[i] ) % mod;
}
}
for( int i = k + 1; i < n; i++ )
ans = ( ans + work(i-k,i) - work(i-k+1,i) + mod ) % mod;
ans = ( ans + work(n-k,n) ) % mod;
cout << ans;
}