HNCPC2024 2024湖南省赛 题解
写在前面
比赛地址:https://codeforces.com/gym/105423。
以下按个人难度向排序。
利益相关:现场赛 Au。
没有和去年一样整场犯唐,好!感谢队友带飞成功一雪前耻。
题解见官方,这里只放一下代码了。
I 签到
复制复制#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long const int N=1e5+5; int read() { int x = 0; bool f = false; char c = getchar(); while(c < '0' || c > '9') f |= (c == '-'), c = getchar(); while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return f ? -x : x; } int n,k,m,q; bool ok[N]; int main() { cin>>n>>k>>m>>q; for(int i=1,x;i<=m;i++){ cin>>x; int now=x; for(int j=1;j<=k;++j){ now%=n; ok[now]=1; now=now*x%n; } } for(int i=1,x;i<=q;i++){ cin>>x; int now=x; bool fl=1; for(int j=1;j<=k;++j){ now%=n; if(ok[now]==0){ fl=0; } now=now*x%n; } cout<<fl<<' '; } return 0; }
C 签到
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long int read() { int x = 0; bool f = false; char c = getchar(); while(c < '0' || c > '9') f |= (c == '-'), c = getchar(); while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return f ? -x : x; } int main() { int n; cin >> n; int cnt = 0; for (int i = 1; i <= n; ++ i) { int a; cin >> a; cnt += log2(a); } double k = 1.0 * cnt / log2(2024); ll ans = ceil(k); cout << ans << "\n"; return 0; }
E 二进制,枚举,子集 DP
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long int read() { int x = 0; bool f = false; char c = getchar(); while(c < '0' || c > '9') f |= (c == '-'), c = getchar(); while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return f ? -x : x; } const int N = 1e6 + 5; int n, a[N], vis[N], num[N]; void solve(int pos) { int S = (1 << (a[pos] - 1)); vis[S] = 1; while(pos < n && !(S & (1 << (a[pos + 1] - 1)))) { ++pos; S |= (1 << (a[pos] - 1)); vis[S] = 1; } } int main() { n = read(); for(int i = 1; i <= n; ++i) a[i] = read(); for(int i = 1; i <= n; ++i) solve(i); int ans = 0, flag = (1 << 18) - 1; for(int i = 1; i <= flag; ++i) num[i] = num[i >> 1] + (i & 1); vis[0] = 1; for(int s = 0; s < (1 << 18); ++s) for(int t = flag ^ s; t; t = (flag ^ s) & (t - 1)) if(vis[s] && vis[t]) ans = max(ans, num[s] + num[t]); printf("%d", ans); return 0; }
K 转化,分层图最短路
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long ll read() { ll x = 0; bool f = false; char c = getchar(); while(c < '0' || c > '9') f |= (c == '-'), c = getchar(); while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return f ? -x : x; } const int N = 2e5 + 5; int n, m, S; vector< pair<int, ll> > V[N]; int vis[N]; ll dis[N]; priority_queue< pair<ll, int> > q; void dijkstra(int S) { q.push(pair<ll, int>(0, S)); for(int i = 1; i <= n * 2; ++i) dis[i] = 0x7fffffffffffffff; while(!q.empty()) { int now = q.top().second ; q.pop(); if(vis[now]) continue; vis[now] = 1; for(auto pp : V[now]) { int v = pp.first ; ll w = pp.second ; if(dis[v] > dis[now] + w) { dis[v] = dis[now] + w; q.push(pair<ll, int>(-dis[v], v)); } } } } int main() { n = read(), m = read(); S = 2 * n + 1; for(int i = 1; i <= m; ++i) { int u = read(), v = read(), w = read(); V[u].emplace_back(pair<int, ll>(v, w)); V[v].emplace_back(pair<int, ll>(u, w)); V[u].emplace_back(pair<int, ll>(v + n, 0)); V[v].emplace_back(pair<int, ll>(u + n, 0)); V[u].emplace_back(pair<int, ll>(u + n, 0)); V[v].emplace_back(pair<int, ll>(v + n, 0)); V[u + n].emplace_back(pair<int, ll>(v + n, w)); V[v + n].emplace_back(pair<int, ll>(u + n, w)); } for(int i = 1; i <= n; ++i) { ll a = read(); V[S].emplace_back(pair<int, ll>(i, a)); } dijkstra(S); ll ans = 0; for(int i = 1; i <= n; ++i) ans = max(ans, dis[i + n]); printf("%lld\n", ans); return 0; }
A 枚举,DP,简单计算几何
#include <bits/stdc++.h> using namespace std; #define LL long long #define ull unsigned long long #define int long long const int kN = 1e3 + 10; const double eps=1e-9; int n,x[kN],y[kN], into[kN]; int ans=0; struct node{ int x,y; }; node get_node(int a,int b){ return (node){x[b]-x[a],y[b]-y[a]}; } int f[55]; double len(node a){ return sqrt(a.x*a.x+a.y*a.y); } bool check(node a,node b,bool fl){ if(fl){ if(a.x*b.y-a.y*b.x<0) return 0; }else{ if(a.x*b.y-a.y*b.x>0) return 0; } double oo=(1.0*a.x*b.x+1.0*a.y*b.y)/(1.00*len(a)*len(b)); if(oo<0-eps) return 0; if(oo-eps>1) return 0; return 1; } void get(node now,bool fl){ for(int i=1;i<=n;++i) f[i]=-9999999; vector<int> edge[kN]; for (int i = 0; i <= n; ++ i) into[i] = 0; for(int i=0;i<=n;++i){ if (!check(get_node(0, i), now, fl)) continue; for(int j=1;j<=n;++j){ if(i==j) continue; if (!check(get_node(0, j), now, fl)) continue; if(check(get_node(i,j),now,fl)){ edge[i].push_back(j); ++ into[j]; } } } queue<int> q; q.push(0); while (!q.empty()) { int u = q.front(); q.pop(); for (auto v: edge[u]) { f[v] = max(f[v], f[u] + 1); if (!(--into[v])) q.push(v); } } for(int i=0;i<=n;++i) ans=max(ans,f[i]); } signed main(){ cin>>n; f[0]=0; x[0]=0,y[0]=0; for(int i=1;i<=n;++i){ cin>>x[i]>>y[i]; if(x[i]==0&&y[i]==0){ f[0]++; --i; --n; } } ans=f[0]; for(int i=0;i<=n;++i){ for(int j=0;j<=n;++j){ if(i==j) continue; get(get_node(i,j),0); get(get_node(i,j),1); } } cout<<ans<<endl; return 0; }
J 单调性,枚举,数据结构
#include <bits/stdc++.h> using namespace std; #define int long long #define ll long long #define ull unsigned long long const int N = 1e6 + 10; int read() { int x = 0; bool f = false; char c = getchar(); while(c < '0' || c > '9') f |= (c == '-'), c = getchar(); while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return f ? -x : x; } int n; int a[N],b[N],ans=0; int ida[N],idb[N]; set<int> s; struct BIT { #define low(x) ((x)&(-x)) int sum[N]; int lim; void init(int lim_) { lim = lim_; for (int i = 1; i <= lim; ++ i) sum[i] = 0; } void insert(int p_, int val_) { for (int i = p_; i <= lim; i += low(i)) { sum[i] += val_; } } int Sum(int p_) { int ret = 0; for (int i = p_; i; i -= low(i)) ret += sum[i]; return ret; } } bit[2]; bool check(int x){ int rka = bit[0].Sum(ida[x]); int rkb = bit[1].Sum(idb[x]); return rka == rkb; } void push(int x){ bit[0].insert(ida[x], 1); bit[1].insert(idb[x], 1); } void del(int x){ bit[0].insert(ida[x], -1); bit[1].insert(idb[x], -1); } signed main() { cin>>n; bit[0].init(n); bit[1].init(n); for(int i=1;i<=n;++i){ cin>>a[i]; ida[a[i]]=i; } for(int i=1;i<=n;++i){ cin>>b[i]; idb[b[i]]=i; } int r=1; push(r); for(int l=1;l<=n;++l){ while(r+1<=n&&check(r+1)){ push(r+1); ++r; } ans+=(r-l+1); del(l); } cout<<ans; return 0; }
H DP,字符串,KMP
#include <bits/stdc++.h> using namespace std; #define LL long long #define ull unsigned long long const int kN = 10010; const LL p = 998244353; int n, k; LL f[kN][13][110]; int fail[110]; int len; char s[110]; int read() { int x = 0; bool f = false; char c = getchar(); while(c < '0' || c > '9') f |= (c == '-'), c = getchar(); while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return f ? -x : x; } int main() { n = read(), k = read(); scanf("%s", s + 1); len = strlen(s + 1); fail[1] = 0; for (int i = 2, j = 0; i <= len; ++ i) { while (j && s[i] != s[j + 1]) j = fail[j]; if (s[i] == s[j + 1]) ++ j; fail[i] = j; } f[0][0][0] = 1; for (int i = 0; i < n; ++ i) { for (int j = 0; j <= k; ++ j) { for (int l = 0; l < len; ++ l) { for (int c = 0; c < 26; ++ c) { bool flag = 0; for (int pre = l; 1; pre = fail[pre]) { if (s[pre + 1] == (char)(c + 'a')) { if (pre == len - 1) { f[i + 1][j + 1][0] += f[i][j][l]; f[i + 1][j + 1][0] %= p; } else { f[i + 1][j][pre + 1] += f[i][j][l]; f[i + 1][j][pre + 1] %= p; } flag = 1; break; } if (pre == 0) break; } if (flag) continue; f[i + 1][j][0] += f[i][j][l]; f[i + 1][j][0] %= p; } } } } // for (int i = 1; i <= n; ++ i) { // for (int j = 0; j <= k; ++ j) { // for (int l = 0; l <= len; ++ l) { //// printf("%d %d %d %lld\n", i, j, l, f[i][j][l]); // } // } // } LL ans = 0; for (int i = 0; i < len; ++ i) { ans += f[n][k][i]; ans %= p; } printf("%lld\n", ans); return 0; } /* 4 1 aa */
D 莫比乌斯反演,枚举
前置知识:莫比乌斯反演。
艾佛森括号:
此处 是一个可真可假的命题。
发现给定的式子需要枚举 并求在分母上的 ,非常丑陋,于是套路地考虑枚举 ,并考虑有多少对 可以对枚举的 产生贡献,想到对 进行莫比乌斯反演。
考虑如下经典的反演套路:
于是考虑枚举 ,原式转化为:
然后发现推不下去了。但是发现 和 实际上是存在对 的约数的关系的,即有 。于是套路地考虑转化枚举对象(这个套路在P3768 简单的数学题 里见过),考虑将枚举 转化为枚举 与 ,则有 ,则上式可转化为:
于是得到了题解的式子。
用到了同样套路的例题推荐:
#include<bits/stdc++.h> using namespace std; #define int long long #define ll long long #define ull unsigned long long int read() { int x = 0; bool f = false; char c = getchar(); while(c < '0' || c > '9') f |= (c == '-'), c = getchar(); while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar(); return f ? -x : x; } const ll mod = 998244353; const int N = 2e5; int n; struct node{ ll a, b; } A[N + 5]; bool cmp(const node &a, const node &b) { return (a.a == b.a ) ? (a.b < b.b ) : (a.a < b.a ); } int vis[N + 5], prime[N + 5], cnt; ll jc[N + 5], inv[N + 5], u[N + 5], f[N + 5]; vector<int> yve[N + 5]; ll qpow(ll a, ll b, ll mod) { ll ans = 1; while(b) { if(b & 1) ans = ans * a % mod; b >>= 1; a = a * a % mod; } return ans; } void init() { u[1] = 1; for(int i = 2; i <= N; ++i) { if(!vis[i]) prime[++cnt] = i, u[i] = -1; for(int j = 1; j <= cnt && prime[j] * i <= N; ++j) { vis[prime[j] * i] = 1; if(i % prime[j] == 0) break; u[i * prime[j]] = -u[i]; } } for(int i = 1; i <= N; ++i) for(int j = 1; j * i <= N; ++j) { f[i * j] = (f[i * j] + u[i] * i * i % mod + mod) % mod; yve[i * j].emplace_back(i); } // 求单个数的逆元 jc[0] = jc[1] = inv[0] = inv[1] = 1; for(int i = 2; i <= N; ++i) jc[i] = jc[i - 1] * i % mod; inv[N] = qpow(jc[N], mod - 2, mod); for(int i = N - 1; i >= 2; --i) inv[i] = inv[i + 1] * (i + 1) % mod; for(int i = 2; i <= N; ++i) inv[i] = inv[i] * jc[i - 1] % mod; for(int i = 2; i <= N; ++i) f[i] = f[i] * inv[i] % mod * inv[i] % mod; } ll Sum1[N + 5], Sum2[N + 5], ans; signed main() { init(); n = read(); for(int i = 1; i <= n; ++i) A[i].a = read(); for(int i = 1; i <= n; ++i) A[i].b = read(); sort(A + 1, A + n + 1, cmp); for(int i = 1; i <= n; ++i) for(auto T : yve[A[i].b ]) { ans = (ans + f[T] * ((A[i].a * A[i].b % mod * Sum2[T] % mod - A[i].b * Sum1[T] % mod + mod) % mod) % mod) % mod; Sum1[T] = (Sum1[T] + A[i].a * A[i].b ) % mod; Sum2[T] = (Sum2[T] + A[i].b ) % mod; } ans = (ans % mod + mod) % mod; printf("%lld\n", ans * 2 % mod); return 0; }
写在最后
回来之后厌学了。
作者@Luckyblock,转载请声明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具