2024年多校联考公益周赛第29场(提高级)
赛时:\(0+0+0\)。
补题:\(100+100+0\)。
T1
hash 即可。
code
#include<bits/stdc++.h> #define ull unsigned long long using namespace std; const int N=1e4+5; const int P=13331; string s,t; int m,ss,tt,ans; ull ps[N],pt[N],hss[N],hst[N]; void hss_init(){ ps[0]=1; for(int i=1;i<=ss;i++){ hss[i]=hss[i-1]*P+s[i]; ps[i]=ps[i-1]*P; } } void hst_init(){ pt[0]=1; for(int i=1;i<=tt;i++){ hst[i]=hst[i-1]*P+t[i]; pt[i]=pt[i-1]*P; } } ull hss_get(int l,int r){ return hss[r]-hss[l-1]*ps[r-l+1]; } ull hss_del(int x){ return hss_get(1,x-1)*ps[ss-x]+hss_get(x+1,ss); } ull hst_get(int l,int r){ return hst[r]-hst[l-1]*pt[r-l+1]; } ull hst_del(int x){ return hst_get(1,x-1)*pt[tt-x]+hst_get(x+1,tt); } int main(){ ios::sync_with_stdio(0); cin>>s>>m; ss=s.size(); s="#"+s; hss_init(); while(m--){ cin>>t; tt=t.size(); t="#"+t; hst_init(); if(hss[ss]==hst[tt]){ ans++; continue; } bool f=0; if(ss<tt){ for(int i=1;i<=tt;i++){ if(hst_del(i)==hss[ss]){ f=1; break; } } } else{ for(int i=1;i<=ss;i++){ if(hss_del(i)==hst[tt]){ f=1; break; } } } if(f) ans++; } cout<<ans; return 0; }
考场寄因:没开 freopen
,并且 没提交。
T2
数数题。
首先题目应该是有个错误,就是要求应该是漂亮值 \(\ge d\)。
考虑边界情况:
-
\(k=0\),答案为 \(n!\)。
-
\(k=n\),若 \(d=0\),答案为 \(n!\),否则为 \(0\)。
接着,我们考虑将 \(>k\) 的数称为 II 类数,其余称为 I 类数。
不妨将连在一起的同一类数看成一个数(一个联通块),这样答案只要在乘上 \(k!(n-k)!\)(就是它们内部的排列总数) 即可。
令总联通块个数为 \(p\)。显然,一个联通块若有 \(n\) 个 II 类数,则其贡献即为 \(n-1\),\(p\) 个联通块的总贡献为 II 类元素个数 \(- \ p\),即 \(n-k-p\)。
由题,\(n-k-p \ge d \to n-k-d \ge p\),得到 \(p \in [1,n-k-d]\),于是枚举 \(p\) 再进行计算。
对于每一个 \(p\),我们可以选出一个 I 类数(反正不会影响答案)单独作为一个联通块,贡献为 \(n\);然后 II 类数 与 I 类数 就交替形成联通块,使用插板法即可求解分的方案数,贡献即为 \(\dfrac{n \times C^{k-1}_{p-1} \times C^{n-k-1}_{p-1}}{p}\)(第一个操作相当于删去了一个联通块,对于每一种方案,都有 \(p\) 中删除方式,而只能对应一个,因此要除以 \(p\)),简单画一下图便可理解上式。
组合数预处理一下阶乘、逆元和阶乘逆元就可以 \(O(1)\) 求出了。
正好有点忘了,补充一下怎么线性求逆元。
求 \(i\) 在 \(\bmod \ p\) 意义下的逆元:
令 \(k = \lfloor \frac{p}{i} \rfloor,r=p \bmod i\)。
于是有 \(k \times i + r \equiv 0(\bmod \ p)\)。
移项:\(k \times i \equiv -r(\bmod \ p)\)
两边 \(\times \ i^{-1} \times r^{-1}\):\(k \times r^{-1} \equiv -i^{-1}(\bmod \ p)\)。
移项:\(i^{-1} \equiv -k \times r^{-1}(\bmod \ p)\)。
替换:\(i^{-1} \equiv -\lfloor \frac{p}{i} \rfloor \times (p \bmod i)^{-1}\)。
为保证 \(i^{-1}\) 为正,右边 \(+ \ p\):\(i^{-1} \equiv (p -\lfloor \frac{p}{i} \rfloor) \times (p \bmod i)^{-1}\)。
然后就可以递推了。
code
#include<bits/stdc++.h> #define int long long using namespace std; const int N=1e6+5; const int MOD=998244353; int t,n,k,d; int fac[N],inv[N],inv_fac[N]; void fac_init(){ fac[0]=inv[1]=inv_fac[0]=1; for(int i=1;i<N;i++) fac[i]=fac[i-1]%MOD*i%MOD; for(int i=2;i<N;i++) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD; for(int i=1;i<N;i++) inv_fac[i]=inv_fac[i-1]%MOD*inv[i]%MOD; } int C(int x,int y){ if(y<0||x<y) return 0; return fac[x]%MOD*inv_fac[y]%MOD*inv_fac[x-y]%MOD; } signed main(){ ios::sync_with_stdio(0); cin>>t; fac_init(); while(t--){ cin>>n>>k>>d; if(!k){ cout<<fac[n]<<'\n'; continue; } else if(k==n){ if(!d) cout<<fac[n]<<'\n'; else cout<<0<<'\n'; continue; } int ans=0; for(int p=1;p<=n-k-d;p++){ if(p==1) ans=(ans+n)%MOD; else ans=(ans+n%MOD*C(k-1,p-1)%MOD*C(n-k-1,p-1)%MOD*inv[p]%MOD)%MOD; } ans=ans%MOD*fac[k]%MOD*fac[n-k]%MOD; cout<<ans<<'\n'; } return 0; }
考场寄因:没有考虑 \(\ge d\) 这个条件。
T3
skip,不补了。
总结
-
要持之以恒地打周考,才能避免保龄的情况。
-
审题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】