2025-12-31~2026-1-1 hetao1733837 的刷题笔记
2025-12-31
居然是 2025 年的最后一篇笔记了吗?可能不是,因为还有一堆草稿......
不过,还是祝自己新年快乐吧!2026 年一定要继续追梦哦!
LG1446 [HNOI2008] Cards
原题链接:[HNOI2008] Cards
分析
被骗了!《算法竞赛》这道题的结论是可以 H a c k Hack Hack 的!
那我看题解......
操,踏🐎的上了大半节课了,起床号才响,ZYZ 赢得相当彻底!
考虑一发 D P DP DP,更确切说是背包,设 f i , j , k f_{i,j,k} fi,j,k 表示三种颜色分别用了多少的方案数。
暴力转移就行了。
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 65;
int fac[N], r, g, b, m, P, n;
int x[N], sz[N], f[N][N][N];
bool vis[N];
int qpow(int a, int b){
int res = 1;
while (b){
if (b & 1)
res = res * a % P;
a = a * a % P;
b >>= 1;
}
return res;
}
void init(){
fac[0] = 1;
for (int i = 1; i < N; i++){
fac[i] = fac[i - 1] * i % P;
}
}
int calc(){
for (int i = 0; i <= r; i++)
for (int j = 0; j <= g; j++)
for (int k = 0; k <= b; k++)
f[i][j][k] = 0;
memset(vis, 0, sizeof(vis));
int tot = 0;
for (int i = 1; i <= n; i++){
if (!vis[i]){
int p = i, len = 0;
while (!vis[p]){
len++;
vis[p] = 1;
p = x[p];
}
sz[++tot] = len;
}
}
f[0][0][0] = 1;
for (int idx = 1; idx <= tot; idx++){
int len = sz[idx];
for (int i = r; i >= 0; i--)
for (int j = g; j >= 0; j--)
for (int k = b; k >= 0; k--){
if (i >= len)
f[i][j][k] = (f[i][j][k] + f[i - len][j][k]) % P;
if (j >= len)
f[i][j][k] = (f[i][j][k] + f[i][j - len][k]) % P;
if (k >= len)
f[i][j][k] = (f[i][j][k] + f[i][j][k - len]) % P;
}
}
return f[r][g][b];
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin >> r >> g >> b >> m >> P;
n = r + g + b;
init();
int ans = 0;
for (int i = 1; i <= m; i++){
for (int j = 1; j <= n; j++){
cin >> x[j];
}
ans = (ans + calc()) % P;
}
for (int j = 1; j <= n; j++){
x[j] = j;
}
ans = (ans + calc()) % P;
int inv = qpow(m + 1, P - 2);
cout << ans * inv % P;
}
这是啥啊!《算法竞赛》一直骗我!
2026-1-1
被卡了两年了。·
LG4980 【模板】Pólya 定理
原题链接:【模板】Pólya 定理
分析
Wishtoday,咋整上离散数学了?
我应该知道公式,然后就是一些小化简。
由 B u r n s i d e Burnside Burnside 引理, 定义 M = { 1 , ... , n } M=\{1,\dots,n\} M={1,...,n} 的可能初始排列,群 G G G 表示旋转 1 → n − 1 1\rightarrow n-1 1→n−1 次。则
a n s = 1 ∣ G ∣ ∑ g ∈ G M g ans=\frac{1}{|G|}\sum\limits_{g\in G}^{}{M^g} ans=∣G∣1g∈G∑Mg
由于在环上,存在一个 gcd \gcd gcd,因而进一步化为
1 n ∑ k = 1 n n gcd ( k , n ) \frac{1}{n}\sum\limits_{k=1}^{n}{n^{\gcd(k,n)}} n1k=1∑nngcd(k,n)
然后上莫比乌斯反演,呃,我并不会
1 n ∑ d ∣ n n d × ∑ k = 1 n d [ gcd ( k , n d ) = = 1 ] \frac{1}{n}\sum\limits_{d|n}{n^d}\times\sum\limits_{k=1}^{\frac{n}{d}}{[\gcd(k,\frac{n}{d})==1]} n1d∣n∑nd×k=1∑dn[gcd(k,dn)==1]
发现后面是个欧拉函数,直接带入
1 n ∑ d ∣ n n d ϕ ( n d ) \frac{1}{n}\sum\limits_{d|n}{n^d\phi(\frac{n}{d})} n1d∣n∑ndϕ(dn)
求就行了......
正解
cpp
#include <bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
int T;
int 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 phi(int x){
int res = x;
for (int i = 2; i <= sqrt(x); i++){
if (x % i != 0)
continue;
res = res - res / i;
while (x % i == 0)
x /= i;
}
if (x != 1)
res = res - res / x;
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> T;
while (T--){
cin >> n;
int k = sqrt(n);
int ans = 0;
for (int i = 1; i <= k; i++){
if (n % i != 0)
continue;
int tmp1 = phi(i);
int tmp2 = qpow(n, n / i);
tmp2 = tmp2 * tmp1 % mod;
ans = (ans + tmp2) % mod;
if (i * i != n){
int tmp3 = phi(n / i);
int tmp4 = qpow(n, i);
tmp4 = tmp4 * tmp3 % mod;
ans = (ans + tmp4) % mod;
}
}
cout << ans * qpow(n, mod - 2) % mod << '\n';
}
}
我找 DeepSeek 再学一下这个东西吧......
2026-1-2
LG2561 [AHOI2002] 黑白瓷砖
原题链接:[AHOI2002] 黑白瓷砖
分析
看了一眼题,觉得可能是拆成一个项链之类的吧......我看看题解吧......
没看懂......
留给明天,先打板子!
板子打完了......还是太抽象了......
稍微懂了一点吧......
就是说,之前那个拆开的是错的,我们直接去考虑题目中给出的神秘三角形,然后会发现有 6 种变化,即不动、旋转×2,翻转×3,手推一发,得出式子
a n s = 1 6 ( 2 N + 2 × 2 ⌈ N 3 ⌉ + 3 × 2 ( N − ⌈ N 2 ⌉ 2 + ⌈ N 2 ⌉ ) ) N = n × ( n + 1 ) 2 ans=\frac{1}{6}(2^N+2\times 2^{\left\lceil\frac{N}{3}\right\rceil}+3\times 2^{(\frac{N-\left\lceil\frac{N}{2}\right\rceil}{2}+\left\lceil\frac{N}{2}\right\rceil)})\\ N=\frac{n\times(n+1)}{2} ans=61(2N+2×2⌈3N⌉+3×2(2N−⌈2N⌉+⌈2N⌉))N=2n×(n+1)
居然要高精度!我*****
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int BS = 10000;
const int N = 205;
int n;
struct node{
int num[N], len;
node() : len(){
memset(num, 0, sizeof(num));
}
int& operator[](int x){
return num[x];
}
const int& operator[](int const &x) const{
return num[x];
}
void print(void){
printf("%d", num[len - 1]);
for (int i = len - 2; ~i; i--)
printf("%04d", num[i]);
}
};
node operator+(node x, node y){
node res;
if (x.len < y.len)
swap(x, y);
res[0] = 0;
for (res.len = 0; res.len < x.len || res[res.len]; res.len++){
res[res.len] += x[res.len] + y[res.len];
if (res[res.len] > BS){
res[res.len + 1] = 1;
res[res.len] -= BS;
}
else{
res[res.len + 1] = 0;
}
}
return res;
}
node operator*(node x, int y){
node res;
res[0] = 0;
for (res.len = 0; res.len < x.len || res[res.len]; res.len++){
res[res.len] += x[res.len] * y;
if (res[res.len] >= BS){
res[res.len + 1] = res[res.len] / BS;
res[res.len] %= BS;
}
else{
res[res.len + 1] = 0;
}
}
while (res.len > 0 && res[res.len - 1] == 0)
res.len--;
return res;
}
node operator/(node x, int y){
for (int i = x.len - 1; ~i; i--){
if (i)
x[i - 1] += (x[i] % y) * BS;
x[i] /= y;
}
while (x.len && !x[x.len - 1])
x.len--;
return x;
}
node a, b, c, ans;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
int aa = n * (n + 1) / 2;
int bb = (aa - (n + 1) / 2) / 2 + (n + 1) / 2;
int cc = (aa + 2) / 3;
a[0] = 1;
a.len = 1;
for (int i = 1; i <= aa; i++){
a = a * 2;
}
b[0] = 1;
b.len = 1;
for (int i = 1; i <= bb; i++){
b = b * 2;
}
b = b * 3;
c[0] = 1;
c.len = 1;
for (int i = 1; i <= cc; i++){
c = c * 2;
}
c = c * 2;
ans = (a + b + c) / 6;
ans.print();
}
LG10031 「Cfz Round 3」Xor with Gcd
原题链接:「Cfz Round 3」Xor with Gcd
分析
对于每个 n n n 的因数 d d d,满足 gcd ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d 的 i i i 的个数为 ϕ ( n d ) \phi(\frac{n}{d}) ϕ(dn)。
当 ϕ ( n d ) \phi(\frac{n}{d}) ϕ(dn) 为偶数的时候,不会对答案产生贡献。
使得 ϕ ( x ) \phi(x) ϕ(x) 为奇数,当且仅当 x = 1 x=1 x=1 或 x = 2 x=2 x=2。
故,当 n n n 为奇数时,答案为 n n n;当 n n n 为偶数时,答案为 n ⊕ n 2 n\oplus \frac{n}{2} n⊕2n。
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
int T;
int n;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> T;
while (T--){
cin >> n;
if (n % 2 == 0)
cout << (n ^ (n / 2ll)) << '\n';
else
cout << n << '\n';
}
}
累了,想睡会......
发了吧,一会再打几道简单题睡觉!