欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > 洛谷P8502题解

洛谷P8502题解

2024/10/24 23:22:17 来源:https://blog.csdn.net/ZHUYINGYE_123456/article/details/139887546  浏览:    关键词:洛谷P8502题解

[problem] \color{blue}{\texttt{[problem]}} [problem]

在这里插入图片描述

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

这题最恶心的地方是卡空间

我们先考虑不卡空间时怎么做。

直接并不好做,我们考虑正难则反,即利用容斥原理。答案应为从 a a a 没有任何限制经过 m m m 条边到 b b b 的方案数减去从 a a a 经过 m m m 条边到 b b b 且必须经过 c c c 的方案数。

自然地,我们会想到用 f m , i , j f_{m,i,j} fm,i,j 表示从 i i i 经过 m m m j j j 的方案数。显然其初始条件 f 0 , i , i = 1 f_{0,i,i}=1 f0,i,i=1

不难得到, f f f 的转移方程为:

f m , i , j = ∑ k → j f m − 1 , i , k f_{m,i,j}=\sum\limits_{k \to j}f_{m-1,i,k} fm,i,j=kjfm1,i,k

其中 k → j k \to j kj 表示节点 k k k 可以到达节点 j j j

很显然,由于每个节点可以到达的节点是一段连续的区间,我们可以用差分来优化我们的 dp \text{dp} dp

表面上看,最终答案似乎就是

f m , a , b − ∑ k = 0 m ( f k , a , c × f m − k , c , b ) f_{m,a,b}-\sum\limits_{k=0}^{m} \left (f_{k,a,c} \times f_{m-k,c,b} \right ) fm,a,bk=0m(fk,a,c×fmk,c,b)

但是,这样的计数是错误的。因为我们可以多次经过 c c c 这个节点,而每一次经过节点 c c c 都会被重复计数。比如在一条途径中,我们在 3 , 7 , 9 3,7,9 3,7,9 次经过节点 c c c,那么我们在 k = 3 , 7 , 9 k=3,7,9 k=3,7,9 时都会把这条途径计入。

怎样避免重复?我们可以强制从 c c c b b b 的路径不能再经过 c c c。那这样会不会导致计数遗漏?不会,因为从 a a a c c c 的路径还是可以重复经过 c c c 的。

于是,我们可以新开一个数组 g m , i , j g_{m,i,j} gm,i,j 表示从 i i i 经过 m m m 条边到 j j j 但不能经过 i i i 的方案数。 g g g 的转移和 f f f 相似,只是 g l , i , i = 0 ( l = 1 , 2 , … , m ) g_{l,i,i}=0(l=1,2,\dots,m) gl,i,i=0(l=1,2,,m)

但是这题卡空间。

我们发现, f f f g g g m m m 时的转移都只和 ( m − 1 ) (m-1) (m1) 有关。于是 f f f g g g 完全可以重复利用,只需要开二维即可。这样是可以满足空间要求的。但是有个问题,就是我们不能随时询问随时回答,因为我们并没有保留任意的 m m m 的状态信息。

怎么办?不能在线回答询问,那就离线!于是主体思路完成。

离线这一点,这题的难度上了一个台阶。

Code \color{blue}{\text{Code}} Code

const int mod=998244353;
inline void add(int &a,int b){a=(a+b>mod?a+b-mod:a+b);
}const int N=510,M=105;
int l[N],r[N],n,q,m;
int f[2][N][N],g[2][N][N];struct Query{int a,b,c,m,ans,f[M],g[M];
}Q[100010];int main(){scanf("%d%d",&n,&q);for(int i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);for(int i=1;i<=q;i++){scanf("%d%d",&Q[i].a,&Q[i].b);scanf("%d%d",&Q[i].c,&Q[i].m);m=max(m,Q[i].m);}for(int i=1;i<=n;i++)f[0][i][i]=g[0][i][i]=1;//initfor(int k=0;k<=m;k++){bool s=(k&1),t=(s^1);//s 表示这一维的信息,t 表示下一维for(int i=1;i<=q;i++){int a=Q[i].a,b=Q[i].b,c=Q[i].c;Q[i].f[k]=f[s][a][c];Q[i].g[k]=g[s][c][b];if (k==Q[i].m) Q[i].ans=f[s][a][b];}memset(f[t],0,sizeof(f[t]));memset(g[t],0,sizeof(g[t]));for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if (r[j]){//可转移 add(f[t][i][l[j]],f[s][i][j]);add(f[t][i][r[j]+1],mod-f[s][i][j]);add(g[t][i][l[j]],g[s][i][j]);add(g[t][i][r[j]+1],mod-g[s][i][j]);}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){add(f[t][i][j],f[t][i][j-1]);add(g[t][i][j],g[t][i][j-1]);}g[t][i][i]=0;}}for(int i=1;i<=q;i++)for(int j=0;j<=Q[i].m;j++)Q[i].ans=(Q[i].ans-1ll*Q[i].f[j]*Q[i].g[Q[i].m-j]%mod)%mod;for(int i=1;i<=q;i++){Q[i].ans=(Q[i].ans+mod)%mod;printf("%d\n",Q[i].ans);}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com