题解:P1393 Mivik 的标题
zhangyaiwei · · 题解
严肃竞选本题最魔怔做法,看完这篇题解还有手感你是这个👍
*注:代码中的状态定义可能和文字中的不同,比如
题意简述
给定一个字符串
答案乘以
解题思路
Subtask 2
看到至少包含一个首先想到可以先钦定再反演,于是定义
则转移为
初始状态
::::info[代码]
#include<bits/stdc++.h>
// #define int long long
using namespace std;
// #define LOCAL
namespace IO{
char *p1,*p2,*p3,buf[100000],buf2[100000];
#ifndef LOCAL
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(buf2,1,p3-buf2,stdout),p3=buf2)
#define putchar(ch) (p3==buf2+100000&&flush(),*p3++=(ch))
struct Manager{
Manager(){p3=buf2;}
~Manager(){flush();}
}_;
#endif
template<typename T>
inline void read(T &x){
int f=1,ch=getchar();x=0;
while(ch!=EOF&&!isdigit(ch)){
if(ch=='-') f=-f;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
x*=f;
}
inline void read(char &ch){
ch=getchar();
}
inline void read(char* s){
int ch=getchar();
while(ch!=EOF&&isspace(ch)) ch=getchar();
while(ch!=EOF&&!isspace(ch)){
*s++=(char)ch;
ch=getchar();
}
*s='\0';
}
template<typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void write(char ch){
putchar(ch);
}
inline void write(const char* s){
while(*s) putchar(*s++);
}
inline void write(char* s){
while(*s) putchar(*s++);
}
template<typename T>
inline void writeln(T x){
write(x),putchar('\n');
}
template<typename T,typename... Args>
inline void read(T &&x,Args&&... args){
read(x),read(std::forward<Args>(args)...);
}
template<typename T,typename... Args>
inline void write(T x,Args... args){
write(x),putchar(' '),write(args...);
}
template<typename T,typename... Args>
inline void writeln(T x,Args... args){
write(x),putchar(' '),writeln(args...);
}
}using namespace IO;
constexpr int N=5005,Mod=998244353;
int m,c,Ic,n,ans,s[N],nxt[N],pw[N],Ipw[N],g[N],fac[N],Inv[N],Ifac[N],f[N][N];
inline int Pow(int a,int b){
int res=1;
while(b){
if(b&1) res=res*1ll*a%Mod;
a=a*1ll*a%Mod;
b>>=1;
}
return res;
}
inline int C(int n,int m){
if(n<0||m<0||n<m) return 0;
return fac[n]*1ll*Ifac[m]%Mod*Ifac[n-m]%Mod;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(m,c,n);
Ic=Pow(c,Mod-2);
for(int i=1;i<=n;i++){
read(s[i]);
}
pw[0]=Ipw[0]=fac[0]=Ifac[0]=Inv[1]=1;
for(int i=1;i<=m;i++){
if(i>1) Inv[i]=(Mod-Mod/i)*1ll*Inv[Mod%i]%Mod;
Ifac[i]=Ifac[i-1]*1ll*Inv[i]%Mod;
fac[i]=fac[i-1]*1ll*i%Mod;
Ipw[i]=Ipw[i-1]*1ll*Ic%Mod;
pw[i]=pw[i-1]*1ll*c%Mod;
}
for(int i=2,j=0;i<=n;i++){
while(j&&s[i]!=s[j+1]) j=nxt[j];
if(s[i]==s[j+1]) ++j;
nxt[i]=j;
}
f[1][0]=(Mod-1)*1ll*pw[m-n]%Mod;
for(int i=1;i<m;i++){
for(int j=0;j<=m;j++){
(f[i][j]+=(Mod-f[i-1][j])*1ll*Ipw[n]%Mod)%=Mod;
for(int k=nxt[n];k&&j-n+k>=0;k=nxt[k]){
(f[i][j]+=(Mod-f[i][j-n+k])%Mod*1ll*Ipw[n-k]%Mod)%=Mod;
}
}
}
ans=pw[m];
for(int i=1;i<=m;i++){
for(int j=0;j<=m-i*n;j++){
ans=(ans+f[i][j]*1ll*C(m-j+i*(1-n),i)%Mod)%Mod;
}
}
write((1+Mod-ans*1ll*Ipw[m]%Mod)%Mod);
}
::::
Subtask 3
考虑套路地将反演的系数、其余随意排列的贡献融合到转移中,此时不再需要统计
初始状态为
此时时间复杂度还是
显然是可以的,定义
则有
令
可以解得
答案呢?注意到
带回求
展开一下
令
然后显然
然后
令
对比
定义
然后移个项
从
::::info[代码]
#include<bits/stdc++.h>
// #define int long long
using namespace std;
// #define LOCAL
namespace IO{
char *p1,*p2,*p3,buf[100000],buf2[100000];
#ifndef LOCAL
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(buf2,1,p3-buf2,stdout),p3=buf2)
#define putchar(ch) (p3==buf2+100000&&flush(),*p3++=(ch))
struct Manager{
Manager(){p3=buf2;}
~Manager(){flush();}
}_;
#endif
template<typename T>
inline void read(T &x){
int f=1,ch=getchar();x=0;
while(ch!=EOF&&!isdigit(ch)){
if(ch=='-') f=-f;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
x*=f;
}
inline void read(char &ch){
ch=getchar();
}
inline void read(char* s){
int ch=getchar();
while(ch!=EOF&&isspace(ch)) ch=getchar();
while(ch!=EOF&&!isspace(ch)){
*s++=(char)ch;
ch=getchar();
}
*s='\0';
}
template<typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void write(char ch){
putchar(ch);
}
inline void write(const char* s){
while(*s) putchar(*s++);
}
inline void write(char* s){
while(*s) putchar(*s++);
}
template<typename T>
inline void writeln(T x){
write(x),putchar('\n');
}
template<typename T,typename... Args>
inline void read(T &&x,Args&&... args){
read(x),read(std::forward<Args>(args)...);
}
template<typename T,typename... Args>
inline void write(T x,Args... args){
write(x),putchar(' '),write(args...);
}
template<typename T,typename... Args>
inline void writeln(T x,Args... args){
write(x),putchar(' '),writeln(args...);
}
}using namespace IO;
constexpr int N=10005,Mod=998244353;
int m,c,Ic,n,ans,s[N],d[N],nxt[N],pw[N],Ipw[N],g[N],fac[N],Inv[N],Ifac[N];
inline int Pow(int a,int b){
int res=1;
while(b){
if(b&1) res=res*1ll*a%Mod;
a=a*1ll*a%Mod;
b>>=1;
}
return res;
}
inline int C(int n,int m){
if(n<0||m<0||n<m) return 0;
return fac[n]*1ll*Ifac[m]%Mod*Ifac[n-m]%Mod;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(m,c,n);
Ic=Pow(c,Mod-2);
for(int i=1;i<=n;i++){
read(s[i]);
}
pw[0]=Ipw[0]=fac[0]=Ifac[0]=Inv[1]=1;
for(int i=1;i<=m;i++){
if(i>1) Inv[i]=(Mod-Mod/i)*1ll*Inv[Mod%i]%Mod;
Ifac[i]=Ifac[i-1]*1ll*Inv[i]%Mod;
fac[i]=fac[i-1]*1ll*i%Mod;
Ipw[i]=Ipw[i-1]*1ll*Ic%Mod;
pw[i]=pw[i-1]*1ll*c%Mod;
}
for(int i=2,j=0;i<=n;i++){
while(j&&s[i]!=s[j+1]) j=nxt[j];
if(s[i]==s[j+1]) ++j;
nxt[i]=j;
}
ans=d[0]=1;
for(int i=1;i<=m-n;i++){
d[i]=d[i-1];
for(int j=nxt[n];j;j=nxt[j]){
int k=n-j;
d[i]=(d[i]+Mod-((i-k>=0?d[i-k]:0)+Mod-(i-k-1>=0?d[i-k-1]:0))%Mod*1ll*Ipw[k]%Mod)%Mod;
}
if(i>=n){
d[i]=(d[i]+Mod-Ipw[n]*1ll*d[i-n]%Mod)%Mod;
}
ans=(ans+d[i])%Mod;
}
write(ans%Mod*1ll*Ipw[n]%Mod);
}
::::
Subtask 4(满分)
还有第三关???
常规的优化似乎已经到了尽头,我们需要发掘一些新性质,通过翻阅题解可得,
递推的瓶颈在于枚举
设
将第二个求和表述成关于
则
于是这道题就做完了,复杂度
::::info[代码]
#include<bits/stdc++.h>
// #define int long long
using namespace std;
// #define LOCAL
namespace IO{
char *p1,*p2,*p3,buf[100000],buf2[100000];
#ifndef LOCAL
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(buf2,1,p3-buf2,stdout),p3=buf2)
#define putchar(ch) (p3==buf2+100000&&flush(),*p3++=(ch))
struct Manager{
Manager(){p3=buf2;}
~Manager(){flush();}
}_;
#endif
template<typename T>
inline void read(T &x){
int f=1,ch=getchar();x=0;
while(ch!=EOF&&!isdigit(ch)){
if(ch=='-') f=-f;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
x*=f;
}
inline void read(char &ch){
ch=getchar();
}
inline void read(char* s){
int ch=getchar();
while(ch!=EOF&&isspace(ch)) ch=getchar();
while(ch!=EOF&&!isspace(ch)){
*s++=(char)ch;
ch=getchar();
}
*s='\0';
}
template<typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void write(char ch){
putchar(ch);
}
inline void write(const char* s){
while(*s) putchar(*s++);
}
inline void write(char* s){
while(*s) putchar(*s++);
}
template<typename T>
inline void writeln(T x){
write(x),putchar('\n');
}
template<typename T,typename... Args>
inline void read(T &&x,Args&&... args){
read(x),read(std::forward<Args>(args)...);
}
template<typename T,typename... Args>
inline void write(T x,Args... args){
write(x),putchar(' '),write(args...);
}
template<typename T,typename... Args>
inline void writeln(T x,Args... args){
write(x),putchar(' '),writeln(args...);
}
}using namespace IO;
constexpr int N=200005,lN=30,Mod=998244353;
int m,c,Ic,n,ans,s[N],d[N],nxt[N],pw[N],Ipw[N],g[N],fac[N],Inv[N],Ifac[N];
int tot,bgn[lN],stp[lN],len[lN],S[lN][N];
inline int Pow(int a,int b){
int res=1;
while(b){
if(b&1) res=res*1ll*a%Mod;
a=a*1ll*a%Mod;
b>>=1;
}
return res;
}
inline int C(int n,int m){
if(n<0||m<0||n<m) return 0;
return fac[n]*1ll*Ifac[m]%Mod*Ifac[n-m]%Mod;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(m,c,n);
Ic=Pow(c,Mod-2);
for(int i=1;i<=n;i++){
read(s[i]);
}
pw[0]=Ipw[0]=fac[0]=Ifac[0]=Inv[1]=1;
for(int i=1;i<=m;i++){
if(i>1) Inv[i]=(Mod-Mod/i)*1ll*Inv[Mod%i]%Mod;
Ifac[i]=Ifac[i-1]*1ll*Inv[i]%Mod;
fac[i]=fac[i-1]*1ll*i%Mod;
Ipw[i]=Ipw[i-1]*1ll*Ic%Mod;
pw[i]=pw[i-1]*1ll*c%Mod;
}
for(int i=2,j=0;i<=n;i++){
while(j&&s[i]!=s[j+1]) j=nxt[j];
if(s[i]==s[j+1]) ++j;
nxt[i]=j;
}
for(int i=nxt[n];i;i=nxt[i]){
stp[++tot]=i-nxt[i],bgn[tot]=n-i,len[tot]=1;
while(nxt[i]&&i-nxt[i]==stp[tot]){
++len[tot];
i=nxt[i];
}
}
ans=d[0]=1;
for(int i=1;i<=m-n;i++){
d[i]=d[i-1];
for(int j=1;j<=tot;j++){
if(i>=bgn[j]){
S[j][i]=d[i-bgn[j]]*1ll*Ipw[bgn[j]]%Mod;
if(i>=stp[j]){
S[j][i]=(S[j][i]+S[j][i-stp[j]]*1ll*Ipw[stp[j]]%Mod)%Mod;
}
if(i>=bgn[j]+len[j]*stp[j]){
S[j][i]=(S[j][i]+Mod-d[i-bgn[j]-len[j]*stp[j]]*1ll*Ipw[bgn[j]+len[j]*stp[j]]%Mod)%Mod;
}
}
d[i]=(d[i]+Mod-(S[j][i]+Mod-S[j][i-1])%Mod)%Mod;
}
if(i>=n){
d[i]=(d[i]+Mod-Ipw[n]*1ll*d[i-n]%Mod)%Mod;
}
ans=(ans+d[i])%Mod;
}
write(ans%Mod*1ll*Ipw[n]%Mod);
}
::::