Compare commits
7
Commits
fa496ca42e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0f909a039 | ||
|
|
483251962e | ||
|
|
67f1f4d5cc | ||
|
|
97ce969ae3 | ||
|
|
fefae6e22b | ||
|
|
53d14446a0 | ||
|
|
101ef331f6 |
+2
-1
@@ -2,6 +2,7 @@
|
|||||||
!*.cpp
|
!*.cpp
|
||||||
!.gitignore
|
!.gitignore
|
||||||
!README.md
|
!README.md
|
||||||
!*.md
|
!solutions
|
||||||
|
!solutions/*.md
|
||||||
!clean.sh
|
!clean.sh
|
||||||
tmp.md
|
tmp.md
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
const int mod = 1e9 + 7;
|
||||||
|
int n, m;
|
||||||
|
int a[100005];
|
||||||
|
const long long fir[4][2] = {{0, 0}, {0, 1}, {0, 2}, {0, 1}};
|
||||||
|
const long long yes[4][4] = {{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 2, 1, 0}, {0, 1, 1, 1}};
|
||||||
|
const long long no[4][4] = {{0, 0, 0, 0}, {0, 1, 0, 1}, {0, 2, 1, 2}, {0, 1, 1, 2}};
|
||||||
|
struct Mat
|
||||||
|
{
|
||||||
|
long long a[5][5] = {};
|
||||||
|
int n, m;
|
||||||
|
Mat(int _n = 0, int _m = 0, int cpy = 0) : n(_n), m(_m)
|
||||||
|
{
|
||||||
|
if (cpy == 1)
|
||||||
|
for (int i = 1; i <= 3; ++i)
|
||||||
|
a[i][1] = fir[i][1];
|
||||||
|
else if (cpy == 2)
|
||||||
|
for (int i = 1; i <= 3; ++i)
|
||||||
|
for (int j = 1; j <= 3; ++j)
|
||||||
|
a[i][j] = yes[i][j];
|
||||||
|
else if (cpy == 3)
|
||||||
|
for (int i = 1; i <= 3; ++i)
|
||||||
|
for (int j = 1; j <= 3; ++j)
|
||||||
|
a[i][j] = no[i][j];
|
||||||
|
}
|
||||||
|
void operator*=(const Mat &b)
|
||||||
|
{
|
||||||
|
if (m != b.n)
|
||||||
|
exit(-1);
|
||||||
|
long long res[5][5] = {};
|
||||||
|
for (int i = 1; i <= n; ++i)
|
||||||
|
for (int j = 1; j <= b.m; ++j)
|
||||||
|
for (int k = 1; k <= m; ++k)
|
||||||
|
res[i][j] = (res[i][j] + a[i][k] * b.a[k][j]) % mod;
|
||||||
|
for (int i = 1; i <= n; ++i)
|
||||||
|
for (int j = 1; j <= b.m; ++j)
|
||||||
|
a[i][j] = res[i][j];
|
||||||
|
m = b.m;
|
||||||
|
}
|
||||||
|
Mat operator*(const Mat &b)
|
||||||
|
{
|
||||||
|
if (m != b.n)
|
||||||
|
exit(-1);
|
||||||
|
Mat res(n, b.m);
|
||||||
|
for (int i = 1; i <= n; ++i)
|
||||||
|
for (int j = 1; j <= b.m; ++j)
|
||||||
|
for (int k = 1; k <= m; ++k)
|
||||||
|
res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]) % mod;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mat qpow(Mat a, long long k)
|
||||||
|
{
|
||||||
|
Mat res(a.n, a.n);
|
||||||
|
for (int i = 1; i <= a.n; ++i)
|
||||||
|
res.a[i][i] = 1;
|
||||||
|
while (k)
|
||||||
|
{
|
||||||
|
if (k & 1)
|
||||||
|
res *= a;
|
||||||
|
a *= a;
|
||||||
|
k >>= 1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
Mat yess(3, 3, 2);
|
||||||
|
Mat noo(3, 3, 3);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
scanf("%d%d", &n, &m);
|
||||||
|
for (int i = 1; i <= m; ++i)
|
||||||
|
scanf("%d", &a[i]);
|
||||||
|
Mat now(3, 1, 1);
|
||||||
|
int pos = 1;
|
||||||
|
for (int i = 1; i <= m; ++i)
|
||||||
|
{
|
||||||
|
int x = a[i];
|
||||||
|
if (x < pos)
|
||||||
|
continue;
|
||||||
|
if (x > pos)
|
||||||
|
{
|
||||||
|
now = qpow(noo, x - pos) * now;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
now = yess * now;
|
||||||
|
}
|
||||||
|
pos = x + 1;
|
||||||
|
}
|
||||||
|
if (n - pos > 0)
|
||||||
|
{
|
||||||
|
now = qpow(noo, n - pos) * now;
|
||||||
|
}
|
||||||
|
printf("%lld\n", now.a[3][1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
const long long MOD = 1000000007LL;
|
||||||
|
|
||||||
|
struct Mat {
|
||||||
|
long long a[105][105];
|
||||||
|
int n, m;
|
||||||
|
|
||||||
|
Mat(int _n = 0, int _m = 0) : n(_n), m(_m) {
|
||||||
|
memset(a, 0, sizeof(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator*=(const Mat &b) {
|
||||||
|
if (m != b.n) {
|
||||||
|
cerr << "矩阵维度不匹配" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
long long res[105][105] = {};
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
for (int j = 1; j <= b.m; ++j) {
|
||||||
|
for (int k = 1; k <= m; ++k) {
|
||||||
|
res[i][j] = (res[i][j] + a[i][k] * b.a[k][j]) % MOD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
for (int j = 1; j <= b.m; ++j) {
|
||||||
|
a[i][j] = res[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m = b.m;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mat qpow(Mat a, long long k) {
|
||||||
|
Mat res(a.n, a.n);
|
||||||
|
for (int i = 1; i <= a.n; ++i) {
|
||||||
|
res.a[i][i] = 1;
|
||||||
|
}
|
||||||
|
while (k) {
|
||||||
|
if (k & 1) res *= a;
|
||||||
|
a *= a;
|
||||||
|
k >>= 1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
long long n;
|
||||||
|
scanf("%lld", &n);
|
||||||
|
|
||||||
|
if (n <= 2) {
|
||||||
|
printf("1\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat base1(1, 2), base2(2, 2);
|
||||||
|
|
||||||
|
base1.a[1][1] = 1;
|
||||||
|
base1.a[1][2] = 1;
|
||||||
|
base2.a[1][1] = 1;
|
||||||
|
base2.a[1][2] = 1;
|
||||||
|
base2.a[2][1] = 1;
|
||||||
|
base2.a[2][2] = 0;
|
||||||
|
base2 = qpow(base2, n - 2);
|
||||||
|
base1 *= base2;
|
||||||
|
printf("%lld\n", base1.a[1][1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
int n, k;
|
||||||
|
int a[100005];
|
||||||
|
int spf[100005]; // 最小质因子
|
||||||
|
vector<int> fac[100005]; // 每个数的质因子列表(带重数)
|
||||||
|
int cnt[100005]; // 当前窗口内每个质数的总指数
|
||||||
|
long long cur, ans;
|
||||||
|
deque<int> dq_max, dq_min;
|
||||||
|
// 计算e的贡献
|
||||||
|
long long gx(int e) {
|
||||||
|
if (e == 0) return 0;
|
||||||
|
long long t = (sqrt(8.0 * e + 1) - 1) / 2;
|
||||||
|
while ((t + 1) * (t + 2) / 2 <= e) ++t;
|
||||||
|
while (t * (t + 1) / 2 > e) --t;
|
||||||
|
return e + t;
|
||||||
|
}
|
||||||
|
// 预处理最小质因子
|
||||||
|
void init_spf() {
|
||||||
|
for (int i = 2; i < 100005; ++i) {
|
||||||
|
if (!spf[i]) {
|
||||||
|
spf[i] = i;
|
||||||
|
if ((long long)i * i < 100005) {
|
||||||
|
for (int j = i * i; j < 100005; j += i) {
|
||||||
|
if (!spf[j]) spf[j] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 分解质因数
|
||||||
|
void get_fac(int idx, int x) {
|
||||||
|
while (x > 1) {
|
||||||
|
int p = spf[x];
|
||||||
|
while (x % p == 0) {
|
||||||
|
fac[idx].push_back(p);
|
||||||
|
x /= p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main() {
|
||||||
|
scanf("%d%d", &n, &k);
|
||||||
|
init_spf();
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
scanf("%d", &a[i]);
|
||||||
|
get_fac(i, a[i]);
|
||||||
|
}
|
||||||
|
int l = 1;
|
||||||
|
cur = 0,ans = 0;
|
||||||
|
for (int r = 1; r <= n; ++r) {
|
||||||
|
// 加入 a[r]
|
||||||
|
for (int p : fac[r]) {
|
||||||
|
int e = cnt[p];
|
||||||
|
cur += gx(e + 1) - gx(e);
|
||||||
|
cnt[p]++;
|
||||||
|
}
|
||||||
|
while (!dq_max.empty() && a[dq_max.back()] <= a[r]) dq_max.pop_back();
|
||||||
|
dq_max.push_back(r);
|
||||||
|
while (!dq_min.empty() && a[dq_min.back()] >= a[r]) dq_min.pop_back();
|
||||||
|
dq_min.push_back(r);
|
||||||
|
// 收缩左边界
|
||||||
|
while (1) {
|
||||||
|
while (!dq_max.empty() && dq_max.front() < l) dq_max.pop_front();
|
||||||
|
while (!dq_min.empty() && dq_min.front() < l) dq_min.pop_front();
|
||||||
|
int mx = a[dq_max.front()];
|
||||||
|
int mn = a[dq_min.front()];
|
||||||
|
if (mx - mn <= k) break;
|
||||||
|
// 移除 a[l]
|
||||||
|
for (int p : fac[l]) {
|
||||||
|
int e = cnt[p];
|
||||||
|
cur += gx(e - 1) - gx(e);
|
||||||
|
cnt[p]--;
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
ans = max(ans, cur);
|
||||||
|
}
|
||||||
|
printf("%lld\n", ans);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
# AT_agc013_e
|
||||||
|
|
||||||
|
[luoshunran](https://www.acwing.com/file_system/file/content/whole/index/content/14321537/)
|
||||||
|
|
||||||
|
## 20 pts O(n)
|
||||||
|
|
||||||
|
把正方形的交界处看作隔板,在每两个隔板之间放入一黑一白两个球,正方形的大小也就等于区间内放入两个球的方案数,正方形的面积的乘积就是所有的放球方案乘法原理乘起来。于是变成了求有多少种放隔板、放球的方案。
|
||||||
|
|
||||||
|
做 dp $f(i, 0/1/2)$,代表目前这个区间内放入了几个球的方案。
|
||||||
|
|
||||||
|
注意 $f(1, 1) = 2$
|
||||||
|
|
||||||
|
若 $i - i + 1$ 之间可以放隔板,
|
||||||
|
|
||||||
|
- $f(i+1, 0) = f(i, 0) + f(i, 2)$
|
||||||
|
- $ f(i+1, 1) = 2 * f(i, 0) + f(i, 1) + 2 * f(i, 2)$, 这里乘以 2 代表决策放入的是黑球还是白球
|
||||||
|
- $ f(i+1, 2) = f(i, 0) + f(i, 1) + 2 * f(i, 2) $
|
||||||
|
|
||||||
|
类似地,也可以列出不可以放隔板的情况。
|
||||||
|
|
||||||
|
- $f(i+1, 0) = f(i, 0)$
|
||||||
|
- $f(i+1, 1) = 2 * f(i, 0) + f(i, 1)$
|
||||||
|
- $f(i+1, 2) = f(i, 0) + f(i, 1) + f(i, 2)$
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
const int mod = 1e9 + 7;
|
||||||
|
int n, m;
|
||||||
|
long long f[5000005][3];
|
||||||
|
int a[100005];
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
scanf("%d%d", &n, &m);
|
||||||
|
for (int i = 1; i <= m; ++i)
|
||||||
|
scanf("%d", &a[i]);
|
||||||
|
sort(a + 1, a + m + 1);
|
||||||
|
int tot = 1;
|
||||||
|
f[1][0] = 1, f[1][1] = 2, f[1][2] = 1;
|
||||||
|
for (int i = 1; i < n; ++i)
|
||||||
|
{
|
||||||
|
if (i == a[tot])
|
||||||
|
{
|
||||||
|
tot++;
|
||||||
|
f[i + 1][0] = f[i][0];
|
||||||
|
f[i + 1][1] = (f[i][0] * 2 + f[i][1]) % mod;
|
||||||
|
f[i + 1][2] = (f[i][0] + f[i][1] + f[i][2]) % mod;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f[i + 1][0] = (f[i][0] + f[i][2]) % mod;
|
||||||
|
f[i + 1][1] = (f[i][0] * 2 + f[i][1] + 2 * f[i][2]) % mod;
|
||||||
|
f[i + 1][2] = (f[i][0] + f[i][1] + f[i][2] * 2) % mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("%lld\n", f[n][2]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 100 pts O(m log n)
|
||||||
|
|
||||||
|
注意到一个区间内需要多次转移,非常浪费。可以考虑使用矩阵快速幂优化。
|
||||||
|
|
||||||
|
对于非标记点,转移矩阵为:
|
||||||
|
|
||||||
|
$$
|
||||||
|
T=\begin{bmatrix}
|
||||||
|
1&0&1\\
|
||||||
|
2&1&2\\
|
||||||
|
1&1&2
|
||||||
|
\end{bmatrix}
|
||||||
|
$$
|
||||||
|
|
||||||
|
对于标记点:
|
||||||
|
|
||||||
|
$$
|
||||||
|
T=\begin{bmatrix}
|
||||||
|
1&0&0\\
|
||||||
|
2&1&0\\
|
||||||
|
1&1&1
|
||||||
|
\end{bmatrix}
|
||||||
|
$$
|
||||||
|
|
||||||
|
初始位置矩阵为:
|
||||||
|
|
||||||
|
$$
|
||||||
|
T=\begin{bmatrix}
|
||||||
|
1\\
|
||||||
|
2\\
|
||||||
|
1
|
||||||
|
\end{bmatrix}
|
||||||
|
$$
|
||||||
|
|
||||||
|
矩阵快速幂代码可参考[P1962](https://luogu.com.cn/problem/P1962)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
const long long MOD = 1000000007LL;
|
||||||
|
struct Mat {
|
||||||
|
long long a[105][105];
|
||||||
|
int n, m;
|
||||||
|
Mat(int _n = 0, int _m = 0) : n(_n), m(_m) {
|
||||||
|
memset(a, 0, sizeof(a));
|
||||||
|
}
|
||||||
|
void operator*=(const Mat &b) {
|
||||||
|
if (m != b.n) {
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
long long res[105][105] = {};
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
for (int j = 1; j <= b.m; ++j) {
|
||||||
|
for (int k = 1; k <= m; ++k) {
|
||||||
|
res[i][j] = (res[i][j] + a[i][k] * b.a[k][j]) % MOD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
for (int j = 1; j <= b.m; ++j) {
|
||||||
|
a[i][j] = res[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m = b.m;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mat qpow(Mat a, long long k) {
|
||||||
|
Mat res(a.n, a.n);
|
||||||
|
for (int i = 1; i <= a.n; ++i) {
|
||||||
|
res.a[i][i] = 1;
|
||||||
|
}
|
||||||
|
while (k) {
|
||||||
|
if (k & 1) res *= a;
|
||||||
|
a *= a;
|
||||||
|
k >>= 1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
long long n;
|
||||||
|
scanf("%lld", &n);
|
||||||
|
|
||||||
|
if (n <= 2) {
|
||||||
|
printf("1\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat base1(1, 2), base2(2, 2);
|
||||||
|
|
||||||
|
base1.a[1][1] = 1;
|
||||||
|
base1.a[1][2] = 1;
|
||||||
|
base2.a[1][1] = 1;
|
||||||
|
base2.a[1][2] = 1;
|
||||||
|
base2.a[2][1] = 1;
|
||||||
|
base2.a[2][2] = 0;
|
||||||
|
base2 = qpow(base2, n - 2);
|
||||||
|
base1 *= base2;
|
||||||
|
printf("%lld\n", base1.a[1][1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
最终程序:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
const int mod = 1e9 + 7;
|
||||||
|
int n, m;
|
||||||
|
int a[100005];
|
||||||
|
const long long fir[4][2] = {{0, 0}, {0, 1}, {0, 2}, {0, 1}};
|
||||||
|
const long long yes[4][4] = {{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 2, 1, 0}, {0, 1, 1, 1}};
|
||||||
|
const long long no[4][4] = {{0, 0, 0, 0}, {0, 1, 0, 1}, {0, 2, 1, 2}, {0, 1, 1, 2}};
|
||||||
|
struct Mat
|
||||||
|
{
|
||||||
|
long long a[5][5] = {};
|
||||||
|
int n, m;
|
||||||
|
Mat(int _n = 0, int _m = 0, int cpy = 0) : n(_n), m(_m)
|
||||||
|
{
|
||||||
|
if (cpy == 1)
|
||||||
|
for (int i = 1; i <= 3; ++i)
|
||||||
|
a[i][1] = fir[i][1];
|
||||||
|
else if (cpy == 2)
|
||||||
|
for (int i = 1; i <= 3; ++i)
|
||||||
|
for (int j = 1; j <= 3; ++j)
|
||||||
|
a[i][j] = yes[i][j];
|
||||||
|
else if (cpy == 3)
|
||||||
|
for (int i = 1; i <= 3; ++i)
|
||||||
|
for (int j = 1; j <= 3; ++j)
|
||||||
|
a[i][j] = no[i][j];
|
||||||
|
}
|
||||||
|
void operator*=(const Mat &b)
|
||||||
|
{
|
||||||
|
if (m != b.n)
|
||||||
|
exit(-1);
|
||||||
|
long long res[5][5] = {};
|
||||||
|
for (int i = 1; i <= n; ++i)
|
||||||
|
for (int j = 1; j <= b.m; ++j)
|
||||||
|
for (int k = 1; k <= m; ++k)
|
||||||
|
res[i][j] = (res[i][j] + a[i][k] * b.a[k][j]) % mod;
|
||||||
|
for (int i = 1; i <= n; ++i)
|
||||||
|
for (int j = 1; j <= b.m; ++j)
|
||||||
|
a[i][j] = res[i][j];
|
||||||
|
m = b.m;
|
||||||
|
}
|
||||||
|
Mat operator*(const Mat &b)
|
||||||
|
{
|
||||||
|
if (m != b.n)
|
||||||
|
exit(-1);
|
||||||
|
Mat res(n, b.m);
|
||||||
|
for (int i = 1; i <= n; ++i)
|
||||||
|
for (int j = 1; j <= b.m; ++j)
|
||||||
|
for (int k = 1; k <= m; ++k)
|
||||||
|
res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]) % mod;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mat qpow(Mat a, long long k)
|
||||||
|
{
|
||||||
|
Mat res(a.n, a.n);
|
||||||
|
for (int i = 1; i <= a.n; ++i)
|
||||||
|
res.a[i][i] = 1;
|
||||||
|
while (k)
|
||||||
|
{
|
||||||
|
if (k & 1)
|
||||||
|
res *= a;
|
||||||
|
a *= a;
|
||||||
|
k >>= 1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
Mat yess(3, 3, 2);
|
||||||
|
Mat noo(3, 3, 3);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
scanf("%d%d", &n, &m);
|
||||||
|
for (int i = 1; i <= m; ++i)
|
||||||
|
scanf("%d", &a[i]);
|
||||||
|
Mat now(3, 1, 1);
|
||||||
|
int pos = 1;
|
||||||
|
for (int i = 1; i <= m; ++i)
|
||||||
|
{
|
||||||
|
int x = a[i];
|
||||||
|
if (x < pos)
|
||||||
|
continue;
|
||||||
|
if (x > pos)
|
||||||
|
{
|
||||||
|
now = qpow(noo, x - pos) * now;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
now = yess * now;
|
||||||
|
}
|
||||||
|
pos = x + 1;
|
||||||
|
}
|
||||||
|
if (n - pos > 0)
|
||||||
|
{
|
||||||
|
now = qpow(noo, n - pos) * now;
|
||||||
|
}
|
||||||
|
printf("%lld\n", now.a[3][1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
# CF1912E Evaluate It and Back Again题解
|
||||||
|
|
||||||
|
## 题意
|
||||||
|
|
||||||
|
给定两个数,要求你写出一个只包含数字, $+, \times, -$ 的式子,正着看是第一个数,反着看是第二个数。
|
||||||
|
|
||||||
|
## 题解
|
||||||
|
|
||||||
|
观察发现只有**一位数**和 $+, \times$ 的**单项式**倒过来读还是一样的,由 $-0$ 结尾的单项式倒过来读和原式结果相反。
|
||||||
|
|
||||||
|
发现可以将一个要求倒着读后数值不变的数表示为 $9$ 进制的形式,这样多项式中每一项都是倒着读后不变的。
|
||||||
|
|
||||||
|
- 对于两个奇偶性相同的数,可以求两个数的平均数,将 $p, q$ 分别表示为 $p = \overline{pq} + \frac{p - q}{2}, q = \overline{pq} - \frac{p - q}{2}$
|
||||||
|
- 对于两个奇偶性不同的数,也可以求平均数,但是为了让 $p, q$ 奇偶性统一,需要给 $p, q$ 分别减去一个正着读是奇数,反着读是偶数的数,如 $12$,然后即可按照第一种形式做
|
||||||
|
|
||||||
|
然后就是注意特判两个相同的数和 `0 0` 的情况,别忘记开 long long 就结束了
|
||||||
|
|
||||||
|
不懂看注释
|
||||||
|
|
||||||
|
## 参考代码
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
string ans;
|
||||||
|
string to_9(long long n) //转换为正反均相同的多项式
|
||||||
|
{
|
||||||
|
bool flag = n >= 0;
|
||||||
|
if (!flag)
|
||||||
|
n = -n;
|
||||||
|
ans = "";
|
||||||
|
long long cnt = 0;
|
||||||
|
long long yu[20] = {};
|
||||||
|
while (n >= 10ll)
|
||||||
|
yu[cnt++] = n % 9ll, n /= 9ll;
|
||||||
|
yu[cnt] = n;
|
||||||
|
if (!flag)
|
||||||
|
ans += "0-";
|
||||||
|
for (long long i = 0; i <= cnt; ++i)
|
||||||
|
{
|
||||||
|
if (yu[cnt - i] != 0)
|
||||||
|
{
|
||||||
|
for (long long j = 0; j < cnt - i; ++j)
|
||||||
|
ans += "9*";
|
||||||
|
ans += yu[cnt - i] + '0';
|
||||||
|
if (flag)
|
||||||
|
ans += "+0+";
|
||||||
|
else
|
||||||
|
ans += "-0-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ans[ans.size() - 1] == '+' || ans[ans.size() - 1] == '-')
|
||||||
|
ans.pop_back(); // 去掉多于符号
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
string to_9_0(long long n) // 转换为正反读相反的多项式
|
||||||
|
{
|
||||||
|
bool flag = n >= 0;
|
||||||
|
if (!flag)
|
||||||
|
n = -n;
|
||||||
|
ans = "";
|
||||||
|
long long cnt = 0;
|
||||||
|
long long yu[20] = {};
|
||||||
|
while (n >= 10)
|
||||||
|
{
|
||||||
|
yu[cnt++] = n % 9ll;
|
||||||
|
n /= 9ll;
|
||||||
|
}
|
||||||
|
yu[cnt] = n;
|
||||||
|
if (!flag)
|
||||||
|
ans += "0-";
|
||||||
|
for (long long i = 0; i <= cnt; ++i)
|
||||||
|
{
|
||||||
|
if (yu[cnt - i] != 0)
|
||||||
|
{
|
||||||
|
for (long long j = 0; j < cnt - i; ++j)
|
||||||
|
ans += "9*";
|
||||||
|
ans += yu[cnt - i] + '0';
|
||||||
|
if (flag)
|
||||||
|
ans += "-0+";
|
||||||
|
else
|
||||||
|
ans += "+0-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ans[ans.size() - 1] == '+' || ans[ans.size() - 1] == '-')
|
||||||
|
ans.pop_back(); // 去掉多于符号
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
long long p = 0, q = 0;
|
||||||
|
scanf("%lld%lld", &p, &q);
|
||||||
|
if (abs(p) % 2 == abs(q) % 2) // 同奇偶
|
||||||
|
{
|
||||||
|
long long _pq = p + q >> 1, p_q = p - _pq;
|
||||||
|
if (p == 0 && q == 0) // 特判
|
||||||
|
{
|
||||||
|
puts("0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cout << to_9(_pq) << ((_pq != 0 && p_q != 0) ? "+" : "") << to_9_0(p_q) << endl;
|
||||||
|
}
|
||||||
|
else // 异奇偶
|
||||||
|
{
|
||||||
|
long long _pq = (p - 21 + q - 12) >> 1, p_q = p - 21 - _pq; // 转换为同奇偶
|
||||||
|
cout << to_9(_pq) << ((_pq != 0 && p_q != 0) ? "+" : "") << to_9_0(p_q) << ((p_q != 0 || _pq != 0) ? "+" : "") << "21" << endl;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# [CF739A Alyona and mex](https://www.luogu.com.cn/problem/CF739A)
|
||||||
|
|
||||||
|
## 题意
|
||||||
|
|
||||||
|
给定 $m$ 个区间,构造出一个长度为 $n$ 的序列,使得这 $m$ 个区间的最小 $mex$ 最大。 $mex$ 定义为最小的没有出现过的自然数。
|
||||||
|
|
||||||
|
## 题解
|
||||||
|
|
||||||
|
先观察样例,发现两次输出的 $mex$ 均等于**最短的区间长度**,显然这不是巧合。
|
||||||
|
|
||||||
|
首先很容易得出 $mex(S) \le \lvert S \rvert$,且当 $S$ 覆盖 $0$ 到 $\lvert S \rvert - 1$ 时取等,所以最终答案不会超过最短的区间的长度,然后思考如何构造出答案等于最短区间长度的情况。
|
||||||
|
|
||||||
|
求出最短的区间长度为 $x$,只要让这个区间完全覆盖 $0, 1, 2, ..., x - 1$ ,就可以取到 $mex$ 的最大值,所以则只要在数组中循环填入 $0, 1, 2, ..., x - 1$,就能保证每一个长度大于等于 $x$ 的区间 $mex$ 一定都等于 $x$,因为每一个长度大于等于 $x$ 的区间都至少覆盖一次 $0, 1, 2, ..., x - 1$。(可以自己手搓几个样例试试)
|
||||||
|
|
||||||
|
## 代码
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int n, m;
|
||||||
|
scanf("%d%d", &n, &m);
|
||||||
|
int minlen = INT_MAX;
|
||||||
|
for (int i = 0; i < m; ++i)
|
||||||
|
{
|
||||||
|
int l, r;
|
||||||
|
scanf("%d%d", &l, &r);
|
||||||
|
minlen = min(minlen, r - l + 1);
|
||||||
|
}
|
||||||
|
printf("%d\n", minlen);
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 1; i <= n; ++i)
|
||||||
|
printf("%d ", i % minlen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
# P13366 [GCJ 2011 #1A] The Killer Word 题解
|
参考了[官方pdf题解](https://www.luogu.com.cn/fe/api/problem/downloadAttachment/zsdw8913)。
|
||||||
|
|
||||||
参考了 [官方pdf题解](https://www.luogu.com.cn/fe/api/problem/downloadAttachment/zsdw8913)
|
|
||||||
|
|
||||||
## 思路
|
## 思路
|
||||||
|
|
||||||
@@ -20,38 +18,26 @@
|
|||||||
|
|
||||||
对于每个长度,初始时将所有该长度的单词放入同一个候选组。
|
对于每个长度,初始时将所有该长度的单词放入同一个候选组。
|
||||||
|
|
||||||
一个候选组表示:
|
一个候选组表示在已经猜过的字母及其反馈下,Sean 仍然无法区分的所有单词。
|
||||||
|
|
||||||
> 在已经猜过的字母及其反馈下,Sean 仍然无法区分的所有单词。
|
|
||||||
|
|
||||||
对于某个字母,使用一个二进制表示它在单词中出现的位置。
|
对于某个字母,使用一个二进制表示它在单词中出现的位置。
|
||||||
|
|
||||||
例如:
|
例如对于单词 banana 和字母 a,对应二进制为 $101010_2$。
|
||||||
|
|
||||||
- 单词 `banana`
|
|
||||||
- 字母 `a`
|
|
||||||
- `a` 出现在第 $1,3,5$ 位(下标从 $0$ 开始)
|
|
||||||
|
|
||||||
则对应二进制为:
|
|
||||||
|
|
||||||
$$
|
|
||||||
0101010_2
|
|
||||||
$$
|
|
||||||
|
|
||||||
两个单词对于当前字母得到相同编码,当且仅当 Sean 从黑板上看到的反馈相同,因此它们应被分到同一个新候选组中。
|
两个单词对于当前字母得到相同编码,当且仅当 Sean 从黑板上看到的反馈相同,因此它们应被分到同一个新候选组中。
|
||||||
|
|
||||||
## 转移过程
|
## 转移过程
|
||||||
|
|
||||||
对于一张字母表 `L`:
|
对于一张字母表 L。
|
||||||
|
|
||||||
1. 按单词长度初始化候选组。
|
1. 按单词长度初始化候选组。
|
||||||
2. 按 `L` 中的顺序枚举每个字母。
|
2. 按 L 中的顺序枚举每个字母。
|
||||||
3. 对每个当前候选组:
|
3. 对每个当前候选组。
|
||||||
- 若组内只剩一个单词,Sean 已经确定答案,不再需要处理该组。
|
- 若组内只剩一个单词,Sean 已经确定答案,不再需要处理该组。
|
||||||
- 计算组内每个单词对当前字母的出现位置二进制表示。
|
- 计算组内每个单词对当前字母的出现位置二进制表示。
|
||||||
- 若所有二进制表示均为 $0$,说明没有候选单词包含该字母,Sean 会跳过该字母,候选组保持不变。
|
- 若所有二进制表示均为 $0$,说明没有候选单词包含该字母,Sean 会跳过该字母,候选组保持不变。
|
||||||
- 否则,Sean 会猜该字母:
|
- 否则,Sean 会猜该字母。
|
||||||
- 二进制为 $0$ 的单词不含该字母,对这些单词的失分加一;
|
- 二进制为 $0$ 的单词不含该字母,对这些单词的失分加一。
|
||||||
- 按二进制表示将原候选组拆分为多个新候选组。
|
- 按二进制表示将原候选组拆分为多个新候选组。
|
||||||
4. 所有字母处理结束后,选择失分最多的单词。
|
4. 所有字母处理结束后,选择失分最多的单词。
|
||||||
5. 若失分相同,保留字典中下标较小的单词即可满足题目的平局规则。
|
5. 若失分相同,保留字典中下标较小的单词即可满足题目的平局规则。
|
||||||
@@ -60,10 +46,6 @@ $$
|
|||||||
|
|
||||||
单词长度最大为 $10$,字母表长度固定为 $26$。
|
单词长度最大为 $10$,字母表长度固定为 $26$。
|
||||||
|
|
||||||
对于每一张字母表,每个单词最多参与 $26$ 次分组,每次计算位置二进制表示需要 $O(10)$。
|
对于每一张字母表,每个单词最多参与 $26$ 次分组,每次计算位置二进制表示。
|
||||||
|
|
||||||
因此总时间复杂度为:
|
因此总时间复杂度为 $O(NM)$,可以通过本题。
|
||||||
|
|
||||||
$$
|
|
||||||
O(M \times 26 \times N \times 10)=O(NM)
|
|
||||||
$$
|
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
## 题意简述
|
||||||
|
|
||||||
|
给定长度为 $n$ 的序列 $a$ 和整数 $k$。选择一个区间 $[l,r]$,满足区间最大值与最小值之差不超过 $k$。
|
||||||
|
|
||||||
|
将区间乘积质因数分解:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\prod_{i=l}^r a_i = \prod_p p^{E_p}。
|
||||||
|
$$
|
||||||
|
|
||||||
|
对于每个质数 $p$,把 $E_p$ 拆成若干个互不相同的正整数 $e_{p,1},e_{p,2},\dots,e_{p,t_p}$,并选取对应的质数幂 $p^{e_{p,i}}$。所有选取的数必须互不相同。
|
||||||
|
|
||||||
|
得分为所有选取数的约数个数之和:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\sum_p \sum_i (e_{p,i}+1)。
|
||||||
|
$$
|
||||||
|
|
||||||
|
求最大得分。
|
||||||
|
|
||||||
|
## 思路分析
|
||||||
|
|
||||||
|
### 单个质数的贡献
|
||||||
|
|
||||||
|
固定一个质数 $p$,设它在区间乘积中的总指数为 $E$。
|
||||||
|
|
||||||
|
若把 $E$ 拆成 $t$ 个互不相同的正整数,则这些数的和至少为
|
||||||
|
|
||||||
|
$$
|
||||||
|
1+2+\cdots+t = \frac{t(t+1)}2。
|
||||||
|
$$
|
||||||
|
|
||||||
|
当 $E \ge \frac{t(t+1)}2$ 时,可以取 $1,2,\dots,t-1$ 以及 $E-\frac{t(t-1)}2$,它们互不相同且总和为 $E$。
|
||||||
|
|
||||||
|
因此最大可行的 $t$ 为满足 $\frac{t(t+1)}2 \le E$ 的最大整数,即
|
||||||
|
|
||||||
|
$$
|
||||||
|
t_{\max} = \left\lfloor \frac{\sqrt{8E+1}-1}{2} \right\rfloor。
|
||||||
|
$$
|
||||||
|
|
||||||
|
对应的得分为
|
||||||
|
|
||||||
|
$$
|
||||||
|
\sum_i (e_i+1) = E + t_{\max}。
|
||||||
|
$$
|
||||||
|
|
||||||
|
定义
|
||||||
|
|
||||||
|
$$
|
||||||
|
gx(E) = E + \left\lfloor \frac{\sqrt{8E+1}-1}{2} \right\rfloor,
|
||||||
|
$$
|
||||||
|
|
||||||
|
则一个质数指数为 $E$ 时的贡献为 $gx(E)$。特别地,$gx(0)=0$。
|
||||||
|
|
||||||
|
### 区间选择
|
||||||
|
|
||||||
|
对于固定的右端点 $r$,如果区间 $[l,r]$ 合法,那么区间 $[l+1,r]$ 也合法,因为子区间的极差不会增大。
|
||||||
|
|
||||||
|
又因为窗口扩大时,每个质数的指数 $E_p$ 只会增加或不增加,同时 $gx(E)$ 单调递增,所以固定 $r$ 时,区间越长得分越高。于是只需要找到最小的合法左端点。
|
||||||
|
|
||||||
|
使用双指针维护滑动窗口。令左端点 $l$ 单调右移,并用两个单调队列分别维护当前窗口的最大值和最小值。当窗口极差超过 $k$ 时,不断右移 $l$,同时删除 $a_l$ 的质因子贡献。
|
||||||
|
|
||||||
|
## 算法流程
|
||||||
|
|
||||||
|
1. 预处理最小质因子 $spf$,用于快速分解每个 $a_i$。
|
||||||
|
2. 将每个 $a_i$ 分解为质因子列表,保留重数。
|
||||||
|
3. 维护滑动窗口 $[l,r]$,其中:
|
||||||
|
- $cnt[p]$ 表示当前窗口内质数 $p$ 的总指数;
|
||||||
|
- $cur$ 表示当前窗口得分 $\sum_p gx(cnt[p])$;
|
||||||
|
- 两个单调队列维护窗口最大值和最小值。
|
||||||
|
4. 枚举右端点 $r$:
|
||||||
|
- 将 $a_r$ 的质因子加入窗口,更新 $cnt$ 和 $cur$;
|
||||||
|
- 将 $r$ 加入单调队列;
|
||||||
|
- 若当前窗口极差超过 $k$,则不断右移 $l$,并删除 $a_l$ 的质因子贡献;
|
||||||
|
- 用当前 $cur$ 更新答案。
|
||||||
|
5. 输出答案。
|
||||||
|
|
||||||
|
## 复杂度分析
|
||||||
|
|
||||||
|
设 $A=\max a_i \le 10^5$。
|
||||||
|
|
||||||
|
- 预处理最小质因子:$O(A \log \log A)$。
|
||||||
|
- 分解所有 $a_i$:总质因子个数为 $O(n \log A)$。
|
||||||
|
- 滑动窗口:每个元素的每个质因子加入一次、删除一次,复杂度 $O(n \log A)$。
|
||||||
|
- 单调队列:$O(n)$。
|
||||||
|
|
||||||
|
总时间复杂度为
|
||||||
|
|
||||||
|
$$
|
||||||
|
O(A \log \log A + n \log A)。
|
||||||
|
$$
|
||||||
|
|
||||||
|
## 参考代码
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int n, k;
|
||||||
|
int a[100005];
|
||||||
|
int spf[100005]; // 最小质因子
|
||||||
|
vector<int> fac[100005]; // 每个数的质因子列表(带重数)
|
||||||
|
int cnt[100005]; // 当前窗口内每个质数的总指数
|
||||||
|
long long cur, ans;
|
||||||
|
deque<int> dq_max, dq_min;
|
||||||
|
|
||||||
|
// 计算 e 的贡献
|
||||||
|
long long gx(int e) {
|
||||||
|
if (e == 0) return 0;
|
||||||
|
long long t = (sqrt(8.0 * e + 1) - 1) / 2;
|
||||||
|
while ((t + 1) * (t + 2) / 2 <= e) ++t;
|
||||||
|
while (t * (t + 1) / 2 > e) --t;
|
||||||
|
return e + t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预处理最小质因子
|
||||||
|
void init_spf() {
|
||||||
|
for (int i = 2; i < 100005; ++i) {
|
||||||
|
if (!spf[i]) {
|
||||||
|
spf[i] = i;
|
||||||
|
if ((long long)i * i < 100005) {
|
||||||
|
for (int j = i * i; j < 100005; j += i) {
|
||||||
|
if (!spf[j]) spf[j] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分解质因数
|
||||||
|
void get_fac(int idx, int x) {
|
||||||
|
while (x > 1) {
|
||||||
|
int p = spf[x];
|
||||||
|
while (x % p == 0) {
|
||||||
|
fac[idx].push_back(p);
|
||||||
|
x /= p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
scanf("%d%d", &n, &k);
|
||||||
|
init_spf();
|
||||||
|
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
scanf("%d", &a[i]);
|
||||||
|
get_fac(i, a[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int l = 1;
|
||||||
|
cur = 0, ans = 0;
|
||||||
|
|
||||||
|
for (int r = 1; r <= n; ++r) {
|
||||||
|
// 加入 a[r]
|
||||||
|
for (int p : fac[r]) {
|
||||||
|
int e = cnt[p];
|
||||||
|
cur += gx(e + 1) - gx(e);
|
||||||
|
cnt[p]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!dq_max.empty() && a[dq_max.back()] <= a[r]) dq_max.pop_back();
|
||||||
|
dq_max.push_back(r);
|
||||||
|
|
||||||
|
while (!dq_min.empty() && a[dq_min.back()] >= a[r]) dq_min.pop_back();
|
||||||
|
dq_min.push_back(r);
|
||||||
|
|
||||||
|
// 收缩左边界
|
||||||
|
while (1) {
|
||||||
|
while (!dq_max.empty() && dq_max.front() < l) dq_max.pop_front();
|
||||||
|
while (!dq_min.empty() && dq_min.front() < l) dq_min.pop_front();
|
||||||
|
|
||||||
|
int mx = a[dq_max.front()];
|
||||||
|
int mn = a[dq_min.front()];
|
||||||
|
|
||||||
|
if (mx - mn <= k) break;
|
||||||
|
|
||||||
|
// 移除 a[l]
|
||||||
|
for (int p : fac[l]) {
|
||||||
|
int e = cnt[p];
|
||||||
|
cur += gx(e - 1) - gx(e);
|
||||||
|
cnt[p]--;
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ans = max(ans, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%lld\n", ans);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user