P7509 撕裂抹消

· · 题解

时间复杂度:O(nk \log p)
我们可以设置两个数组,分别为 dpgg 是作为概率进行辅助的计算,每一个状态都可在前一个状态进行转移。而 dp 数组怎么打相信我不用多说了吧。
根据题意,可以打出状态转移方程:

dp(i,j,0) = (1 - p(i)) \times (dp(i - 1,j,1) + p(i - 1,j,0)) dp(i,j,1)=p(i) \times (dp(i - 1,j,1) + g(i - 1,j,1) \times a(i)) + p(i) \times (dp(i - 1,j - 1,0) + g(i - 1,j - 1,0) \times a(i)) $j$: 当先连续的段数 运算符重载中的除法重载用快速幂即可。 附上最长本题代码: ```cpp #include<bits/stdc++.h> using namespace std; const long long mo=998244353; const long long MAX_N=1e5+5,MAX_M=25; inline int read(){ long long x=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return x; }//读入优化 long long kkksc03(long long x,long long y){ long long s=1; while (y!=0){ if (y%2==1) s=s*x%mo; x=x*x%mo; y/=2; } return s; }//快速幂 struct kira{ long long x; kira(long long x=0):x(x){}; kira operator=(const long long &xx){ x=xx; return *this; } kira operator+(const kira &b){ return (kira)((x+b.x)%mo); } kira operator-(const kira &b){ return (kira)((x-b.x+mo)%mo); } kira operator*(const kira &b){ return (kira)((x*b.x)%mo); } kira operator/(const kira &b){ return (kira)(x*kkksc03(b.x,mo-2)%mo); } kira operator^(const kira &b){ return (kira)(kkksc03(x,b.x)); } kira operator+=(const kira &b){ return (kira)((x+b.x)%mo); } kira operator-=(const kira &b){ return (kira)((x-b.x+mo)%mo); } kira operator*=(const kira &b){ return (kira)((x*b.x)%mo); } kira operator/=(const kira &b){ return (kira)(x*kkksc03(b.x,mo-2)%mo); } kira operator^=(const kira &b){ return (kira)(kkksc03(x,b.x)); } kira operator+(const long long &b){ return (kira)((x+b)%mo); } kira operator-(const long long &b){ return (kira)((x-b+mo)%mo); } kira operator*(const long long &b){ return (kira)((x*b)%mo); } kira operator/(const long long &b){ return (kira)(x*kkksc03(b,mo-2)%mo); } kira operator^(const long long &b){ return (kira)(kkksc03(x,b)); } kira operator+=(const long long &b){ return (kira)((x+b)%mo); } kira operator-=(const long long &b){ return (kira)((x-b+mo)%mo); } kira operator*=(const long long &b){ return (kira)((x*b)%mo); } kira operator/=(const long long &b){ return (kira)(x*kkksc03(b,mo-2)%mo); } kira operator^=(const long long &b){ return (kira)(kkksc03(x,b)); } bool operator==(const long long b){ return x==b; } };//超级变态的运算符重载 long long n,m,i,k; kira a[MAX_N],p[MAX_N],u,g[MAX_N][MAX_M][2],dp[MAX_N][MAX_M][2],gundam; int main(){ n=read();m=read(); for (i=1;i<=n;i++) a[i]=read(); for (i=1;i<=n;i++) p[i]=read();//手打读入 g[0][0][0]=1;//初始化 u=1;//因为某些灵异事件(类型不相等事件),必须要这么定一个。 for (i=1;i<=n;i++) for (k=0;k<=m;k++) if (k==0) g[i][k][0]=g[i-1][k][0]*(mo+1-p[i].x); else{ if (k+k-1>i) continue; else if (k+k-1==i){ g[i][k][1]=g[i-1][k-1][0]*p[i]; dp[i][k][1]=dp[i-1][k-1][0]+a[i]; } else{ g[i][k][1]=g[i-1][k-1][0]*p[i]+g[i-1][k][1]*p[i]; gundam=u/(g[i-1][k-1][0]+g[i-1][k][1]); dp[i][k][1]=a[i]+dp[i-1][k-1][0]*g[i-1][k-1][0]*gundam+dp[i-1][k][1]*g[i-1][k][1]*gundam; g[i][k][0]=(g[i-1][k][1]+g[i-1][k][0])*(mo+1-p[i].x); gundam=u/(g[i-1][k][0]+g[i-1][k][1]); dp[i][k][0]=dp[i-1][k][0]*g[i-1][k][0]*gundam+dp[i-1][k][1]*g[i-1][k][1]*gundam;//都懂的 } } printf("%lld\n",(dp[n][m][0]*g[n][m][0]+dp[n][m][1]*g[n][m][1]).x); return 0; } ```