2024省选联测11
A. Giao 徽的烤鸭
给定一棵树,边权为 \(1\)。在第 \(i\) 家店办卡花费 \(w_i\) 元。对于任意一家店,如果 Giao 徽在到 \(i\) 的距离小于等于 \(p\) 的所有店办了卡,可得到 \(v_p\) 元的代金券。求最大利润。
\(f_{u,i}\) 表示在以 \(u\) 为根的子树中,到 \(u\) 距离小于等于 \(i\) 的最大利润。
要求父节点第二维 \(\ge i - 1\),儿子第二维 \(\ge i - 1\)。
\(f_{u,i}+=\max(f_{v,i-1},f_{v,i},f_{v,i+1})\)
初始化 \(f_{u,i}=v_i-w_u\)。
注意考虑不选的情况。
点击查看代码
void dfs(int u, int fa)
{
for(int i = 1; i <= n; ++ i) f[u][i] = b[i - 1] - a[u];
for(int i = head[u], v; i; i = e[i].nex)
{
if((v = e[i].to) == fa) continue; dfs(v, u);
f[u][0] += max(f[v][0], f[v][1]);
for(int j = 1; j <= n; ++ j)
f[u][j] += max(f[v][j - 1], max(f[v][j], f[v][j + 1]));
}
}
B. A Dance of Fire and Ice
有一个数 \(val\),初始值为 \(1\)。\(n\) 次操作,每次赋值或者 \(val \times x \bmod p\),\(p\) 是质数。选出任意操作并以任意顺序执行操作。问最终 \(val\) 有多少种可能的取值。
用原根转换成加法,bitset 优化背包就能过了。好像还可以二分哈希,但是我不会。
点击查看代码
#include <cstdio>
#include <bitset>
#include <algorithm>
#define int long long
using namespace std;
const int N = 200005;
bitset <N> f, h;
int n, g, ans, mod, phi, tot, F[N], val[N], vis[N];
int Pow(int x, int y)
{
int r = 1; for(; y; y >>= 1, x = x * x % mod)
if(y & 1) r = r * x % mod; return r;
}
void init(int x)
{
if(x > 0) F[++tot] = x;
for(int i = 2; i * i <= x; ++ i) if(x % i == 0)
F[++tot] = i, i != x / i ? F[++tot] = x / i : 0;
}
bool check(int x)
{
for(int i = 1; i <= tot; ++ i)
if(Pow(x, phi / F[i]) == 1) return 0;
return 1;
}
signed main()
{
freopen("dance.in", "r", stdin);
freopen("dance.out", "w", stdout);
scanf("%lld%lld", &mod, &n); init(phi = mod - 1);
for(int i = 2; i < mod; ++ i)
if(Pow(i, phi) == 1 && check(i)) {g = i; break;}
for(int i = 0, j = 1; i < mod; ++ i, j = j * g % mod) val[j] = i;
f[0] = 1;
for(int i = 1, o, x; i <= n; ++ i)
{
scanf("%lld%lld", &o, &x); x %= mod;
if(!x) ++ ans;
else o == 0 ? f[val[x]] = 1 : vis[val[x]] ++;
}
for(int i = 0; i < mod; ++ i)
{
while(vis[i] --)
{
h = f | (f << i) | (f >> (mod - 1 - i));
if(h == f) break; f = h;
}
}
for(int i = 0; i < mod - 1; ++ i) if(f[i]) ++ ans;
printf("%lld", ans);
fclose(stdin);
fclose(stdout);
return 0;
}
C. 挖掘机技术哪家强
\(n\) 个数,\(a_i=i\)。每次把 \(a_x\) 和 \(a_{x+1}\) 连边,并且交换。问最大团。
暴力 dfs 可得到 60pts。
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 200005;
int n, m, ans, f[N], a[N], b[N], id[N], vis[N];
vector <int> e[N];
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
void init()
{
for(int i = 1; i <= n; ++ i)
f[i] = i, vis[i] = 0;
}
bool dfs(int x)
{
if(vis[x])
return false;
vis[x] = 1;
for(int i = find(1); i < x; i = find(i + 1))
{
if(find(e[x].begin(), e[x].end(), i) != e[x].end())
continue;
f[i] = find(i + 1);
if(!b[i] || dfs(b[i]))
return a[x] = i, b[i] = x, true;
}
return false;
}
int main()
{
freopen("excavator.in", "r", stdin);
freopen("excavator.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i)
id[i] = i;
for(int i = 1, x; i <= m; ++ i)
{
scanf("%d", &x);
e[max(id[x], id[x + 1])].push_back(min(id[x], id[x + 1]));
swap(id[x], id[x + 1]);
}
for(int i = 1; i <= n; ++ i)
{
sort(e[i].begin(), e[i].end());
e[i].erase(unique(e[i].begin(), e[i].end()), e[i].end());
}
vector <int> vec;
for(int i = 1; i <= n; ++ i)
{
for(int x : vec)
{
if(find(e[i].begin(), e[i].end(), x) == e[i].end())
{
ans --;
a[i] = x;
b[x] = i;
vec.erase(find(vec.begin(), vec.end(), x));
break;
}
}
vec.push_back(i);
}
for(int i = 1; i <= n; ++ i)
if(!a[i])
init(), ans -= dfs(i);
printf("%d\n", ans + n);
return 0;
}

浙公网安备 33010602011771号