赛时:\(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)\) 求出了。
正好有点忘了,补充一下怎么线性求逆元。
求 \(b\) 在 \(\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,不补了。
总结
-
要持之以恒地打周考,才能避免保龄的情况。
-
审题。