2023.11.3 做题记录
AcWing.97 约数之和
约数个数定理
对一个大于1的整数$n$,$n$可以分解质因数为$\prod_{i=1}^{k}p_i^{a_i} = {p_1}^{a_1}·{p_2}^{a_2}···{p_k}^{a_k}$
则n的正约数的个数就是$f(n) = \prod_{i=1}^{k}a_i+1=(a_1+1)(a_2+1)···(a_k+1)$,这个很好证明,因为$p_1^{a_1}$的约数有$p_1^0,p_1^1,p_1^2…p_1^{a1}$,共$(a_1+1)$个,同理$p_k^{a_k}$的约数有$(a_k+1)$个
约数定理
$n$的$(a_1+1)(a_2+1)···(a_k+1)$个正约数的和为:
$$
(p_1^0+p_1^1+…+p_1^{a_1})(p_2^0+p_2^1+…p_2^{a_2})…(p_k^0+p_k^1+…p_k^{a_k})
$$
对于这题来说,根据约数定理就有$A^B$的约数和为:
$$
(1+p_1^1+…+p_1^{Ba_1})(1+p_2^1+…p_2^{Ba_2})…(1+p_k^1+…p_k^{Ba_k})
$$
定义calc(n,k)
为$p^0+p^1+…+p^k$,当 $k$ 为偶数,分成两部分的和变为$(p^0+…+p^{\frac{k}{2}})+(p^{\frac{k}{2}+1}+…p^k)$
后面的多项式提取$p^{\frac{k}{2}+1}$,变成$(p^0+…+p^{\frac{k}{2}})+p^{\frac{k}{2}+1} * (p^0+…p^{\frac{k}{2}})$
将两项合并$(1+p^{\frac{k}{2}+1}) * (p^0+…+p^{\frac{k}{2}})$,这个式子可以转化为$(1+p^{\frac{k}{2}}) * calc(p, \frac{k}{2})$
当 $k$ 为奇数时。即 $calc(p, k - 1)+p^{k-1}$
#include<bits/stdc++.h>
#define rint register int
#define int long long
#define endl '\n'
using namespace std;
const int mod = 9901;
int a, b;
int ans = 1;
//保存质因子以及出现的次数
unordered_map<int, int> primes;
void divide(int n)
{
for(int i = 2; i <= n / i; i++)
{
if(n % i == 0)
{
while(n % i == 0)
{
primes[i]++;
n /= i;
}
}
}
if(n > 1)
{
primes[n]++;
}
}
int qpow(int a, int b)
{
int res = 1;
while(b)
{
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int calc(int p, int k)
{
if(k == 1) return 1;
if(k % 2 == 0)
{
return (qpow(p, k / 2) + 1) * calc(p, k / 2) % mod;
}
return (qpow(p, k - 1) + calc(p, k - 1)) % mod;
}
signed main()
{
cin >> a >> b;
divide(a);
for(auto i : primes)
{
int p = i.first;
int k = i.second * b;
ans = ans * calc(p, k + 1) % mod;
}
if (a == 0)
{
cout << 0 << endl;
return 0;
}
cout << ans << endl;
return 0;
}
[HNOI2003] 激光炸弹
二维前缀和即可:
\(f[i][j]=f[i−1][j]+f[i][j−1]−f[i−1][j−1]+a[i][j]\)
细节见代码:
#include <bits/stdc++.h>
#define rint register int
#define endl '\n'
using namespace std;
const int N = 5e3 + 5;
int s[N][N];
int n, m;
int max_x, max_y;
int ans;
signed main()
{
cin >> n >> m;
max_x = max_y = m;
for (rint i = 1; i <= n; i++)
{
int x, y, z;
cin >> x >> y >> z;
x++, y++;
s[x][y] += z;
//如果不是 += z,可能出现重标记情况
//洛谷数据太水,s[x][y] = z 也能过
max_x = max(max_x, x);
max_y = max(max_y, y);
//初始化
//二维前缀和不能便输入边存答案
}
for (rint i = 1; i <= max_x; i++)
{
for (rint j = 1; j <= max_y; j++)
{
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + s[i][j];
}
}
for (rint i = m; i <= max_x; i++)
{
for (rint j = m; j <= max_y; j++)
{
ans = max(ans, s[i][j] - s[i][j - m] - s[i - m][j] + s[i - m][j - m]);
}
}
cout << ans << endl;
return 0;
}
Acwing.128 文本编译器
题目传送门
开两个栈即可:
-
I x
:把 \(x\) 插入栈 \(A\),更新栈 \(A\) 的栈顶位置的前缀和,更新栈 \(A\) 的栈顶位置的最大前缀和
-
D
:弹出栈 \(A\) 的栈顶元素
-
L
:弹出栈 \(A\) 的栈顶元素并插入栈 \(B\) 中
-
R
:弹出栈 \(B\) 的栈顶元素并插入栈 \(A\) 中,更新栈 \(A\) 的栈顶位置的前缀和,更新栈 \(A\) 的栈顶位置的最大前缀和
-
Q k
:直接返回f[k]
SP4354 雪花
暴力 hash
即可
但是从每一个角都存一遍显然会寄,所以考虑对整个序列求和求积,然后对一个大质数取模得到 hash
值,存储上可以采用邻接表。