垃圾银川毁我青春害我生命。
A
最开始以为素数的间隔大约是 l o g log log级别的,所以里面至少有一个素数,结果就被WA飞了,实际上大力SAI来打表发现素数间隔最大能到200+,那就只能想办法减小这个间隔,实际上你选取一点小的素数,让你判定的集合不只是素数,还包括 2 p , 3 p , 5 p , 7 p , 13 p 2p, 3p, 5p, 7p, 13p 2p,3p,5p,7p,13p这些,那这样最小的间隔就减小到了 99 99 99,然后就可以暴力检查了。(为啥选这些呢,因为可以打表尝试啊x)
#include <cstdio>
#include <set>
#include <iostream>
#include <vector>
#include <algorithm>
using ll = long long;
/DEBUG
int const M = 100000;
int PRI[M], tot = 0;
bool vis[M];
void SAI() {
vis[1] = 1;
for (int i = 2; i < M; ++i) {
if (vis[i] == 0)
PRI[tot++] = i;
for (int j = 0; j < tot && PRI[j] * i < M; ++j) {
vis[i * PRI[j]] = 1;
if (i % PRI[j] == 0)
break;
}
}
}
int phi(int x) {
int ret = 1;
for (int i = 2; i * i <= x; ++i)
if (x % i == 0) {
ret *= i - 1;
while ((x /= i) % i == 0)
ret *= i;
}
if (x != 1)
ret *= x - 1;
return ret;
}
bool is_prime (int x) {
switch (x) {
default:
if (x % 2 == 0 || x % 3 == 0 || x % 5 == 0)
case 1: case 4: case 6: case 8: case 9:
return false;
if (x < M)
return !vis[x];
for (int i = 3; i < tot && (ll)PRI[i] * PRI[i] <= x; ++i)
if (x % PRI[i] == 0)
return false;
case 2: case 3: case 5: case 7:
return true;
}
}
const std::vector<int> pri = { 2, 3, 5, 7, 13 };
const int MX = 150000000;
int solve (std::vector<int> const &v) {
int n = v.size();
std::set<int> mp;
for (int i = 0; i < n; ++i) {
for (int p: pri)
if (v[i] % (p - 1) == 0) {
int ppp = v[i] / (p - 1) + 1;
ll orig = (ll)p * ppp;
if (orig > MX)
continue;
int dx = orig - i;
if (dx >= 1 && is_prime(ppp))
mp.insert(dx);
}
int dx = v[i] + 1 - i;
if (dx >= 1 && is_prime(v[i] + 1))
mp.insert(dx);
}
for (int dx: mp) {
bool orz = false;
for (int i = 1; i < n; ++i)
if (v[i] > dx + i - 1) {
orz = true;
break;
}
if (orz)
continue;
for (int i = 0; i < n; ++i)
if (phi(dx + i) != v[i]) {
orz = true;
break;
}
if (!orz)
return dx;
}
return -1;
}
int main () {
std::ios::sync_with_stdio(false);
SAI();
int t;
std::cin >> t;
const int n = 100;
auto v = std::vector<int>(n);
while (t--) {
for (auto &c: v)
std::cin >> c;
int ans = solve(v);
if (ans == -1)
std::cout << "NO\n";
else
std::cout << "YES\n" << ans << '\n';
}
return 0;
}
B
出题人英语本当上手啦!
简单最短路题,大力dij就好啦!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <utility>
using namespace std;
using ll = long long;
using pli = pair<ll, int>;
int const N = 1005;
ll const INF = N * 100000000ll;
struct edge {
int y, w, next;
} e[N * N * 2];
int last[N], ne = 0;
void addedge(int x, int y, int c) {
e[++ne].y = y;
e[ne].w = c;
e[ne].next = last[x];
last[x] = ne;
}
bool vis[N];
int ot[N];
void SPFA(int S, ll dis[], int n) {
priority_queue<pli, vector<pli>, greater<pli> > Q;
for (int i = 1; i <= n; ++i)
vis[i] = 0, dis[i] = INF;
dis[S] = 0;
Q.push(make_pair(0ll, S));
while (Q.empty() == 0) {
pli now = Q.top();
Q.pop();
if (vis[now.second])
continue;
vis[now.second] = 1;
for (int i = last[now.second]; i; i = e[i].next) {
if (dis[e[i].y] > dis[now.second] + e[i].w) {
dis[e[i].y] = dis[now.second] + e[i].w;
Q.push(make_pair(dis[e[i].y], e[i].y));
}
}
}
}
ll dis1[N], dis2[N];
int main() {
ios::sync_with_stdio(0);
int T;
cin >> T;
while (T--) {
int n, m, S, K, C;
cin >> n >> m >> S >> K >> C;
int T = n + 1;
for (int i = 1; i <= T; ++i)
last[i] = 0;
ne = 0;
for (int i = 1; i <= K; ++i) {
cin >> ot[i];
addedge(T, ot[i], 0);
}
for (int i = 1; i <= m; ++i) {
int x, y, c;
cin >> x >> y >> c;
addedge(x, y, c);
addedge(y, x, c);
}
SPFA(T, dis1, n + 1);
SPFA(S, dis2, n);
ll ans1 = *max_element(dis1 + 1, dis1 + n + 1);
ll ans2 = *max_element(dis2 + 1, dis2 + n + 1);
if (ans1 * C < ans2)
cout << ans1 << '\n';
else
cout << ans2 << '\n';
}
}
C
鬼才hello题,网友们也是牛逼,过了那么多但是我啃不动,网友们都是能7分钟打爆tourist的人
终于补完了,感觉是个牛逼东西。
首先我们要证一件事才可以,那就是对于先加再取min的矩阵乘法(如果没理解这是啥可以去看代码)是构成semi-group的。
但是这个证明和矩阵乘法一样证就行,注意单位元是主对角线全0,其他的都是INF的矩阵。
话说貌似只有平凡的子群(只有一个单位元的集合)?
不过有了这件事情,我们就能做这题了。
先把字符串逆序,那么就变成了出现2019而不出现2018的了。
然后我们认为每次从i-1转移到i是乘了一个转移矩阵。
考虑倍增,从左端点倍增到右端点,因为状态数只有5个,就是目前已经拼出了
?
2019
?2019
?2019的前几个。
那么我们来写一下每次的转移矩阵。
首先如果是其他数字的话,显然是乘这个东西的单位元。
如果是
2
2
2 ,显然就是
f
[
i
]
[
0
]
=
f
[
i
−
1
]
[
0
]
+
1
,
f
[
i
]
[
1
]
=
m
i
n
(
f
[
i
−
1
]
[
1
]
,
f
[
i
−
1
]
[
0
]
)
f[i][0] = f[i -1][0] + 1, f[i][1] = min(f[i - 1][1], f[i - 1][0])
f[i][0]=f[i−1][0]+1,f[i][1]=min(f[i−1][1],f[i−1][0])
对应的矩阵就是
(
1
0
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
)
\left( \begin{array}{ccc} 1 & 0 & INF & INF & INF \\ INF & 0 & INF & INF & INF \\ INF & INF & 0 & INF & INF \\ INF & INF & INF & 0 & INF \\ INF & INF & INF & INF & 0 \\ \end{array} \right)
⎝⎜⎜⎜⎜⎛1INFINFINFINF00INFINFINFINFINF0INFINFINFINFINF0INFINFINFINFINF0⎠⎟⎟⎟⎟⎞
如果是
0
0
0 ,显然就是
f
[
i
]
[
1
]
=
f
[
i
−
1
]
[
1
]
+
1
,
f
[
i
]
[
2
]
=
m
i
n
(
f
[
i
−
1
]
[
2
]
,
f
[
i
−
1
]
[
1
]
)
f[i][1] = f[i -1][1] + 1, f[i][2] = min(f[i - 1][2], f[i - 1][1])
f[i][1]=f[i−1][1]+1,f[i][2]=min(f[i−1][2],f[i−1][1])
对应的矩阵就是
(
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
1
0
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
)
\left( \begin{array}{ccc} 0 & INF & INF & INF & INF \\ INF & 1 & 0 & INF & INF \\ INF & INF & 0 & INF & INF \\ INF & INF & INF & 0 & INF \\ INF & INF & INF & INF & 0 \\ \end{array} \right)
⎝⎜⎜⎜⎜⎛0INFINFINFINFINF1INFINFINFINF00INFINFINFINFINF0INFINFINFINFINF0⎠⎟⎟⎟⎟⎞
如果是
1
1
1 ,显然就是
f
[
i
]
[
2
]
=
f
[
i
−
1
]
[
2
]
+
1
,
f
[
i
]
[
3
]
=
m
i
n
(
f
[
i
−
1
]
[
3
]
,
f
[
i
−
1
]
[
2
]
)
f[i][2] = f[i -1][2] + 1, f[i][3] = min(f[i - 1][3], f[i - 1][2])
f[i][2]=f[i−1][2]+1,f[i][3]=min(f[i−1][3],f[i−1][2])
对应的矩阵就是
(
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
1
0
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
)
\left( \begin{array}{ccc} 0 & INF & INF & INF & INF \\ INF & 0 & INF & INF & INF \\ INF & INF & 1 & 0 & INF \\ INF & INF & INF & 0 & INF \\ INF & INF & INF & INF & 0 \\ \end{array} \right)
⎝⎜⎜⎜⎜⎛0INFINFINFINFINF0INFINFINFINFINF1INFINFINFINF00INFINFINFINFINF0⎠⎟⎟⎟⎟⎞
如果是
9
9
9 ,显然就是
f
[
i
]
[
3
]
=
f
[
i
−
1
]
[
3
]
+
1
,
f
[
i
]
[
4
]
=
m
i
n
(
f
[
i
−
1
]
[
4
]
,
f
[
i
−
1
]
[
3
]
)
f[i][3] = f[i -1][3] + 1, f[i][4] = min(f[i - 1][4], f[i - 1][3])
f[i][3]=f[i−1][3]+1,f[i][4]=min(f[i−1][4],f[i−1][3])
对应的矩阵就是
(
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
1
0
I
N
F
I
N
F
I
N
F
I
N
F
0
)
\left( \begin{array}{ccc} 0 & INF & INF & INF & INF \\ INF & 0 & INF & INF & INF \\ INF & INF & 0 & INF & INF \\ INF & INF & INF & 1 & 0 \\ INF & INF & INF & INF & 0 \\ \end{array} \right)
⎝⎜⎜⎜⎜⎛0INFINFINFINFINF0INFINFINFINFINF0INFINFINFINFINF1INFINFINFINF00⎠⎟⎟⎟⎟⎞
如果是
8
8
8 ,那么必须要删掉才行。也就是
f
[
i
]
[
3
]
=
f
[
i
−
1
]
[
3
]
+
1
,
f
[
i
]
[
4
]
=
f
[
i
−
1
]
[
4
]
+
1
f[i][3] = f[i -1][3] + 1, f[i][4] = f[i - 1][4] + 1
f[i][3]=f[i−1][3]+1,f[i][4]=f[i−1][4]+1
对应的矩阵就是
(
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
0
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
1
I
N
F
I
N
F
I
N
F
I
N
F
I
N
F
1
)
\left( \begin{array}{ccc} 0 & INF & INF & INF & INF \\ INF & 0 & INF & INF & INF \\ INF & INF & 0 & INF & INF \\ INF & INF & INF & 1 & INF \\ INF & INF & INF & INF & 1 \\ \end{array} \right)
⎝⎜⎜⎜⎜⎛0INFINFINFINFINF0INFINFINFINFINF0INFINFINFINFINF1INFINFINFINFINF1⎠⎟⎟⎟⎟⎞
初始矩阵显然是
(
0
I
N
F
I
N
F
I
N
F
I
N
F
)
\left( \begin{array}{ccc} 0 & INF & INF & INF & INF \\ \end{array} \right)
(0INFINFINFINF)
#include <iostream>
#include <cstdio>
#include <limits>
#include <algorithm>
using namespace std;
int const INF = numeric_limits<int>::max() >> 1;
struct matrix {
int a[5][5];
matrix () {
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 5; ++j)
a[i][j] = i == j ? 0 : INF;
}
matrix operator * (matrix const& oth) const {
matrix ret;
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 5; ++j) {
ret.a[i][j] = INF;
for (int k = 0; k < 5; ++k)
ret.a[i][j] = min(ret.a[i][j], a[i][k] + oth.a[k][j]);
}
return ret;
}
};
int const N = 200005;
int const LOGN = 20;
matrix f[N][20];
char s[N];
int n, m;
int main() {
scanf("%d%d", &n, &m);
scanf("%s", s);
reverse(s, s + n);
for (int i = n; i >= 1; --i) {
char c = s[i - 1];
if (c == '2') {
f[i][0].a[0][0] = 1;
f[i][0].a[0][1] = 0;
}
if (c == '0') {
f[i][0].a[1][1] = 1;
f[i][0].a[1][2] = 0;
}
if (c == '1') {
f[i][0].a[2][2] = 1;
f[i][0].a[2][3] = 0;
}
if (c == '9') {
f[i][0].a[3][3] = 1;
f[i][0].a[3][4] = 0;
}
if (c == '8') {
f[i][0].a[3][3] = 1;
f[i][0].a[4][4] = 1;
}
for (int j = 1; j < LOGN; ++j)
if (i + (1 << j) - 1 <= n)
f[i][j] = f[i][j - 1] * f[i + (1 << (j - 1))][j - 1];
}
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
l = n - l + 1, r = n - r + 1;
swap(l, r);
auto ans = matrix();
for (int i = LOGN - 1; i >= 0; --i)
if (l + (1 << i) - 1 <= r) {
ans = ans * f[l][i];
l += 1 << i;
}
if (ans.a[0][4] != INF)
printf("%d\n", ans.a[0][4]);
else
puts("-1");
}
}
D
把
F
F
F展开发现
F
n
=
1
−
a
n
1
−
a
F_n = \frac{1 - a^n}{1 - a}
Fn=1−a1−an
也就是对于每个
k
k
k,单独求
∑
∣
s
∣
=
k
a
s
u
m
(
s
)
\sum_{|s| = k} a^{sum(s)}
∑∣s∣=kasum(s)
显然大力卷积就好了,但是因为模数比较鬼才,所以只能FFT
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <complex>
using namespace std;
using ll = long long;
int const TT = 100003, G = 2;
ll const mod = TT;
double const PI = acos(-1.0);
int const N = 400005;
inline int KSM (int a, int k) {
int ret = 1 % TT;
for (; k; k >>= 1, a = 1ll * a * a % TT)
if (k & 1)
ret = 1ll * ret * a % TT;
return ret;
}
inline int add (int x, int y) {
if (x + y >= TT)
return x + y - TT;
else
return x + y;
}
inline int sub (int x, int y) {
if (x - y >= 0)
return x - y;
else
return x - y + TT;
}
namespace Polynom
{
typedef complex <double> cp;
cp a[N], b[N], omg[N], inv[N];
void init (int n) {
for(int i = 0; i < n; i++) {
a[i] = { 0, 0 };
b[i] = { 0, 0 };
omg[i] = cp(cos(2 * PI * i / n), sin(2 * PI * i / n));
inv[i] = conj(omg[i]);
}
}
void FFT (cp *a, cp *omg, int n) {
int lim = 0;
while((1 << lim) < n) lim++;
for(int i = 0; i < n; i++){
int t = 0;
for(int j = 0; j < lim; j++)
if((i >> j) & 1) t |= (1 << (lim - j - 1));
if(i < t) swap(a[i], a[t]); // i < t 的限制使得每对点只被交换一次(否则交换两次相当于没交换)
}
for(int l = 2; l <= n; l *= 2){
int m = l / 2;
for(cp *p = a; p != a + n; p += l)
for(int i = 0; i < m; i++){
cp t = omg[n / l * i] * p[i + m];
p[i + m] = p[i] - t;
p[i] += t;
}
}
}
vector<int> operator * (vector<int> f, vector<int> g) {
int n = 1, m = (int)f.size() + (int)g.size() - 1;
while (n < m)
n <<= 1;
init(n);
for(int i = 0; i < (int)f.size(); ++i)
a[i].real(f[i]);
for(int i = 0; i < (int)g.size(); ++i)
b[i].real(g[i]);
FFT(a, omg, n);
FFT(b, omg, n);
for (int i = 0; i < n; ++i)
a[i] = a[i] * b[i];
FFT(a, inv, n);
f.resize(m);
for (int i = 0; i < m; ++i)
f[i] = (ll)floor(a[i].real() / n + 0.5) % mod;
return f;
}
}
using Polynom::operator *;
int s[N], a;
vector<int> solve (int l, int r) {
if (l == r)
return { 1, KSM(a, s[l]) };
int mid = (l + r) >> 1;
auto f1 = solve(l, mid);
auto f2 = solve(mid + 1, r);
return f1 * f2;
}
int fac[N];
int C(int n, int m) {
return 1ll * fac[n] * KSM(fac[m], mod - 2) % mod * KSM(fac[n - m], mod - 2) % mod;
}
int main() {
ios::sync_with_stdio(0);
int n, Q;
cin >> n >> a >> Q;
for (int i = 1; i <= n; ++i)
cin >> s[i];
fac[0] = 1;
for (int i = 1; i <= n; ++i)
fac[i] = 1ll * fac[i - 1] * i % mod;
auto ans = solve(1, n);
for (int i = 1; i <= n; ++i)
ans[i] = (mod + ans[i] - C(n, i)) * KSM(mod + a - 1ll, mod - 2) % mod;
while (Q--) {
int t;
cin >> t;
cout << ans[t] << '\n';
}
}
E
#include <iostream>
#include <vector>
int divup (int a, int b) {
return (a + b - 1) / b;
}
int rank (int n, int m, int i) {
if (i % m == 0)
return i / m;
int round = divup(n, m);
int n2 = n - round;
int i2 = i - divup(i, m) - (m - n % m) % m;
i2 = (i2 + n2) % n2;
int ret = rank(n2, m, i2) + round;
return ret;
}
int main () {
std::ios::sync_with_stdio(false);
int t;
std::cin >> t;
while (t--) {
int n, m, q;
std::cin >> n >> m >> q;
while (q--) {
int x;
std::cin >> x;
int ans = rank(n, m + 1, x - 1) + 1;
std::cout << ans << '\n';
}
}
return 0;
}
F
日哦,用scanf读最后的字符我竟然用char,几个字母之后就开始读回车了x。
因为是对于T的每一个子串,所以T如果出现重复子串也是算多次,那么也就是每个固定的串在整个串里的概率固定,所以就直接用SAM去重子串,每次的贡献是
m
x
[
p
a
r
[
x
]
]
+
1
mx[par[x]]+1
mx[par[x]]+1到
m
x
[
x
]
mx[x]
mx[x]这一段,每个数为
(
n
−
i
+
1
)
∗
2
6
n
−
i
∗
f
(
i
)
(n - i + 1) * 26 ^ {n - i} * f(i)
(n−i+1)∗26n−i∗f(i)的贡献,预处理一下累加就行。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
inline int read() {
int x = 0;
char ch = getchar();
while (ch < '0' || ch > '9')
ch = getchar();
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}
int const mod = 998244353;
int const N = 400005;
int KSM(int a, int k) {
int ret = 1;
for (; k; k >>= 1, a = 1ll * a * a % mod)
if (k & 1)
ret = 1ll * ret * a % mod;
return ret;
}
int ch[N][26], par[N], mx[N];
int sam_cnt, sam_last;
int sum[N];
void SAM_init(int n) {
sam_cnt = sam_last = 1;
++n;
memset(ch, 0, sizeof(ch[0]) * n);
memset(par, 0, sizeof(par[0]) * n);
memset(mx, 0, sizeof(mx[0]) * n);
}
int SAM_extend(int x) {
int p, q, np, nq;
p = sam_last;
sam_last = np = ++sam_cnt;
mx[np] = mx[p] + 1;
for(; p && !ch[p][x]; p = par[p]) ch[p][x] = np;
if(!p) par[np] = 1;
else {
q = ch[p][x];
if(mx[q] == mx[p] + 1) par[np] = q;
else {
nq = ++sam_cnt;
mx[nq] = mx[p] + 1;
memcpy(ch[nq], ch[q], sizeof(ch[q]));
par[nq] = par[q];
par[q] = par[np] = nq;
for(; ch[p][x] == q; p = par[p]) ch[p][x] = nq;
}
}
return sam_last;
}
int f[N];
inline int calc(int n, int x) {
int ret = 0, t = 1;
for (int i = 0; i <= n; ++i) {
int c = f[i];
ret += 1ll * t * c % mod;
if (ret >= mod)
ret -= mod;
t = 1ll * t * x % mod;
}
return ret;
}
char s[N];
int main() {
int Q = read();
while (Q--) {
int l = read(), k = read(), n = read(), m = read();
scanf("%s", s);
for (int i = 0; i <= k; ++i)
f[i] = read();
sum[0] = f[0];
for (int i = 1; i <= min(n, m + l); ++i) {
int t = 1ll * (n - i + 1) * KSM(KSM(26, i), mod - 2) % mod * calc(k, i) % mod;
sum[i] = sum[i - 1] + t;
if (sum[i] >= mod)
sum[i] -= mod;
}
int ans = 0;
SAM_init((m + l) << 1);
for (int i = 0; i < l; ++i) {
char c = s[i];
sam_last = SAM_extend(c - 'a');
int r = mx[sam_last], l = mx[par[sam_last]];
r = min(r, n);
l = min(l, n);
ans = (1ll * ans + sum[r] - sum[l] + mod) % mod;
}
printf("%d\n", ans);
for (int o = 0; o < m; ++o) {
scanf("%s", s);
sam_last = SAM_extend(s[0] - 'a');
int r = mx[sam_last], l = mx[par[sam_last]];
r = min(r, n);
l = min(l, n);
ans = (1ll * ans + sum[r] - sum[l] + mod) % mod;
printf("%d\n", ans);
}
}
}
G
#include <iostream>
int main() {
int t;
std::cin >> t;
while(t--) {
int n;
std::cin >> n;
std::cout << (n == 1 ? 18000 : 0) << '\n';
}
return 0;
}
H
O ( 1 ) O(1) O(1)快速幂牛逼题, 2 16 2^{16} 216进制快速幂,前面就是简单的待定系数法
#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;
using ll = long long;
int const mod = 998244353;
int const sq17 = 473844410;
int const inv2 = (mod + 1) / 2;
int const k1 = (-3ll + sq17) * inv2 % mod;
int const k2 = (-3ll - sq17 + mod + mod) * inv2 % mod;
int const fm = (k1 - k2 + mod) % mod;
int const invfm = 438914993;
static_assert((ll)sq17 * sq17 % mod == 17, "orz 17");
static_assert(k1 == 736044380, "orz k1");
static_assert(k2 == 262199970, "orz k2");
static_assert((ll)inv2 * 2 % mod == 1, "orz inv2");
static_assert((ll)invfm * fm % mod == 1, "orz fm");
int tbl[4][1 << 16];
void init(int p, int t[][1 << 16]) {
t[0][0] = 1;
for (int i = 1; i < (1 << 16); ++i)
t[0][i] = (ll)t[0][i - 1] * p % mod;
p = (ll)t[0][0xFFFF] * p % mod;
t[1][0] = 1;
for (int i = 1; i < (1 << 16); ++i)
t[1][i] = (ll)t[1][i - 1] * p % mod;
}
int pow32(int t[][1 << 16], int q) {
return (ll)t[0][q & 0xFFFF] * t[1][q >> 16] % mod;
}
int pow64(int t[][1 << 16], ll q) {
return pow32(t, q % (mod - 1));
}
int pow64_f(int p, ll q) {
int ret = 1;
for (; q; p = (ll)p * p % mod, q >>= 1)
if (q & 1)
ret = (ll)ret * p % mod;
return ret;
}
inline int solve(ll n) {
int fz = pow64(tbl + 2, n) - pow64(tbl, n);
// int fz = pow64_f(mod - k2, n) - pow64_f(mod - k1, n);
if (fz < 0)
fz += mod;
return (ll)fz * invfm % mod;
}
int main() {
init(mod - k1, tbl);
init(mod - k2, tbl + 2);
int Q;
int ans = 0, anss = 0;
ll n;
cin >> Q >> n;
// Q = 10000000, n = 1000000000000000000ll;
for (int i = 1; i <= Q; ++i) {
n ^= (ll)ans * ans;
ans = solve(n);
// std::cerr << n << ' ' << ans << '\n';
anss ^= ans;
}
cout << anss << '\n';
// std::cerr << clock() << "<\n";
return 0;
}
I
cdq分治或者动态主席树。
内存比较鬼才。。。N乘,208倍RE,209倍RE,220倍MLE,215倍MLE,211倍AC(
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdlib>
using namespace std;
inline int read() {
int d = 0;
char s = getchar();
while (s < '0' || s > '9')
s = getchar();
while ('0' <= s && s <= '9') {
d = d * 10 + s - '0';
s = getchar();
}
return d;
}
int const N = 200005;
struct seg_node {
int l, r, s;
} t[N * 211];
int tot;
int root[N], root1[N];
int a[N];
int n, m;
void insert(int &lk, int k, int l, int r, int pos, int v) {
lk = ++tot;
t[lk] = t[k];
t[lk].s += v;
if (l == r)
return;
int mid = (l + r) >> 1;
if (pos <= mid)
insert(t[lk].l, t[k].l, l, mid, pos, v);
else
insert(t[lk].r, t[k].r, mid + 1, r, pos, v);
}
int bag1[20], bag2[20], cnt1, cnt2;
// bool flag;
int query(int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
int ret = 0;
for (int i = 1; i <= cnt1; ++i)
ret -= t[bag1[i]].s;
for (int i = 1; i <= cnt2; ++i)
ret += t[bag2[i]].s;
return ret;
}
int mid = (l + r) >> 1;
if (ql <= mid && qr > mid) {
int tmp1[20], tmp2[20], ret = 0;
for (int i = 1; i <= cnt1; ++i) {
tmp1[i] = bag1[i];
bag1[i] = t[bag1[i]].l;
}
for (int i = 1; i <= cnt2; ++i) {
tmp2[i] = bag2[i];
bag2[i] = t[bag2[i]].l;
}
ret += query(l, mid, ql, qr);
for (int i = 1; i <= cnt1; ++i)
bag1[i] = t[tmp1[i]].r;
for (int i = 1; i <= cnt2; ++i)
bag2[i] = t[tmp2[i]].r;
ret += query(mid + 1, r, ql, qr);
return ret;
}
if (ql <= mid) {
for (int i = 1; i <= cnt1; ++i)
bag1[i] = t[bag1[i]].l;
for (int i = 1; i <= cnt2; ++i)
bag2[i] = t[bag2[i]].l;
return query(l, mid, ql, qr);
}
if (qr > mid) {
for (int i = 1; i <= cnt1; ++i)
bag1[i] = t[bag1[i]].r;
for (int i = 1; i <= cnt2; ++i)
bag2[i] = t[bag2[i]].r;
return query(mid + 1, r, ql, qr);
}
return 0;
}
void change(int pos, int v) {
if (a[pos] == v)
return;
int x = -1;
if (a[pos] != a[pos - 1])
for (x = pos; x <= n; x += x & -x)
insert(root1[x], root1[x], 1, n, a[pos], -1);
if (v != a[pos - 1])
for (x = pos; x <= n; x += x & -x)
insert(root1[x], root1[x], 1, n, v, 1);
if (pos < n && a[pos] == a[pos + 1])
for (x = pos + 1; x <= n; x += x & -x)
insert(root1[x], root1[x], 1, n, a[pos + 1], 1);
if (pos < n && v == a[pos + 1])
for (x = pos + 1; x <= n; x += x & -x)
insert(root1[x], root1[x], 1, n, v, -1);
a[pos] = v;
}
inline int get_ans(int l, int r, int x, int y) {
int ad = (x <= a[l]) & (a[l] <= y);
cnt1 = 1;
cnt2 = 1;
bag1[1] = root[l];
bag2[1] = root[r];
for (; l; l -= l & -l)
bag1[++cnt1] = root1[l];
for (; r; r -= r & -r)
bag2[++cnt2] = root1[r];
return query(1, n, x, y) + ad;
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; ++i) {
a[i] = read();
if (a[i] != a[i - 1])
insert(root[i], root[i - 1], 1, n, a[i], 1);
else
root[i] = root[i - 1];
}
for (int o = 0; o < m; ++o) {
int op = read();
if (op & 1) {
int pos = read(), v = read();
change(pos, v);
} else {
int l = read(), r = read(), x = read(), y = read();
int ans = get_ans(l, r, x, y);
printf("%d\n", ans);
}
}
}