Codeforces923E Perpetual Subtraction
Description
- 黑板上有一个整数 ,初始时它的值为 中的某一个整数,其中为 的概率是 。
- 每一轮你可以将 完全随机地替换成 中的一个数。
- 求 轮后,对于每个 , 的概率。
- ,,答案对 取模。
Solution
设 表示经过 轮得到数字 的概率,显然有
使用 来刻画这个过程,那么写出来 看一看
省略了一步等比数列求和,问题不大
注意到 两者相减就是改变积分下界
代换 来避免 和非零下界,那么:
那么如果得到了 可以快速得到 ,使用二项式定理和二项式反演即可得到 以及 的变换,具体而言:
全部是减法卷积
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for(int i=a;i<=b;++i)
const int mod=998244353;
inline int add(int x,int y,int Mod=mod){return x+y>=Mod?x+y-Mod:x+y;}
inline int del(int x,int y,int Mod=mod){return x-y<0?x-y+Mod:x-y;}
inline int mul(int x,int y,int Mod=mod){return x*y-x*y/Mod*Mod;}
inline void ckadd(int &x,int y,int Mod=mod){x=x+y>=Mod?x+y-Mod:x+y;}
inline void ckdel(int &x,int y,int Mod=mod){x=x-y<0?x-y+Mod:x-y;}
inline void ckmul(int &x,int y,int Mod=mod){x=x*y-x*y/Mod*Mod;}
inline int ksm(int x,int y,int Mod=mod){int res=1; for(;y;y>>=1,ckmul(x,x,Mod)) if(y&1) ckmul(res,x,Mod); return res;}
inline void approx(int val,int Mod=mod,int lim=1e5){int x=val,y=Mod,a=1,b=0; while(x>lim){swap(x,y); swap(a,b); a-=x/y*b; x%=y;} cout<<x<<"/"<<a<<endl; return ;}
const int N=5e5+10;
#define poly vector<int>
int r[N],W[N];
int fac[N],ifac[N],inv[N],p[N],n,m;
inline void NTT(vector<int> &f,int lim,int opt){
f.resize(lim);
for(int i=0;i<lim;++i){
r[i]=r[i>>1]>>1|((i&1)?(lim>>1):0);
if(i<r[i]) swap(f[i],f[r[i]]);
}
for(int p=2;p<=lim;p<<=1){
int len=p>>1; W[0]=1; W[1]=ksm(3,(mod-1)/p);
if(opt==-1) W[1]=ksm(W[1],mod-2);
for(int j=2;j<len;++j) W[j]=mul(W[j-1],W[1]);
for(int k=0;k<lim;k+=p){
for(int l=k;l<k+len;++l){
int tt=mul(f[l+len],W[l-k]);
f[l+len]=del(f[l],tt);
ckadd(f[l],tt);
}
}
}
if(opt==-1) for(int i=0,tmp=ksm(lim,mod-2);i<lim;++i) ckmul(f[i],tmp);
return ;
}
inline poly Mul(poly a,poly b){
int n=a.size(),m=b.size(),lim=1;
while(lim<=(n+m)) lim<<=1;
NTT(a,lim,1); NTT(b,lim,1);
for(int i=0;i<lim;++i) ckmul(a[i],b[i]);
NTT(a,lim,-1);
a.resize(n+m-1);
return a;
}
signed main(){
n=5e5; fac[0]=inv[0]=1;
for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
ifac[n]=ksm(fac[n],mod-2);
for(int i=n;i>=1;--i) ifac[i-1]=mul(ifac[i],i),inv[i]=mul(ifac[i],fac[i-1]);
scanf("%lld%lld",&n,&m);
for(int i=0;i<=n;++i) scanf("%lld",&p[i]);
poly A(n+1),B(n+1),G(n+1);
for(int i=0;i<=n;i++) A[i]=ifac[i],B[n-i]=mul(fac[i],p[i]);
poly C=Mul(A,B);
for(int i=0;i<=n;i++) G[i]=mul(ksm(inv[i+1],m),mul(ifac[i],C[n-i]));
A.clear(); B.clear();
A.resize(n+1); B.resize(n+1);
for(int i=0;i<=n;i++){
if(!(i&1)) A[i]=ifac[i];
else A[i]=del(0,ifac[i]);
B[n-i]=mul(fac[i],G[i]);
}
C=Mul(A,B);
for(int i=0;i<=n;i++) printf("%lld ",mul(C[n-i],ifac[i]));
putchar('\n');
return 0;
}
本题另有知识门槛比较高的相似对角化相关做法,比较关键的一点是注意到上三角矩阵的特征值就是对角线上元素
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律