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,不补了。

总结

  • 要持之以恒地打周考,才能避免保龄的情况。

  • 审题。

posted @   _XOFqwq  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示