用户工具

站点工具


2020-2021:teams:legal_string:组队训练比赛记录:contest17

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:legal_string:组队训练比赛记录:contest17 [2021/08/30 21:35]
jxm2001
2020-2021:teams:legal_string:组队训练比赛记录:contest17 [2021/09/05 10:20] (当前版本)
jxm2001 [题意]
行 6: 行 6:
 |  C  |  0  |  0  |  0  |  |  C  |  0  |  0  |  0  | 
 |  D  |  0  |  0  |  0  |  ​ |  D  |  0  |  0  |  0  |  ​
-|  E  |  2  |  ​ ​| ​ 0  |  ​+|  E  |  2  |  ​ ​| ​ 0  |  ​
 |  H  |  2  |  0  |  0  |  ​ |  H  |  2  |  0  |  0  |  ​
-|  J  |  ​ ​| ​ 0  |  0  | +|  J  |  ​ ​| ​ 0  |  0  | 
 |  M  |  0  |  0  |  0  | |  M  |  0  |  0  |  0  |
  
行 18: 行 18:
  
 $$ $$
-\sum_{i=1}^n\sum_{j=1}^n {i+j\choose j}f(i,j)\\+\sum_{i=1}^n\sum_{j=1}^n {i+j\choose j}f(i+j,i)\\
 f(i,j)= f(i,j)=
 \begin{cases} \begin{cases}
行 40: 行 40:
  
 $$ $$
-(f(i+j,j),f(i+j-1,j))=(a,​0)A^{i-1}B^j+(f(i+j,i),f(i+j-1,i))=(a,​0)A^{i-1}B^j
 $$ $$
  
行 48: 行 48:
 \begin{equation}\begin{split} ​ \begin{equation}\begin{split} ​
 S(i+1)&​=\sum_{j=1}^n {i+j+1\choose j}A^iB^j \\  S(i+1)&​=\sum_{j=1}^n {i+j+1\choose j}A^iB^j \\ 
-&​=\sum_{j=1}^n \left({i+j\choose j}+{i+j\choose j+1}\right)A^iB^j\\  +&​=\sum_{j=1}^n \left({i+j\choose j}+{i+j\choose j-1}\right)A^iB^j\\  
-&​=AS(i)+\sum_{j=0}^{n-1}{i+j\choose j}A^{i-1}B^jB\\ ​+&​=AS(i)+\sum_{j=0}^{n-1}{i+j+1\choose j}A^{i}B^jB\\ ​
 & =AS(i)+\left(S(i+1)+A^i-{i+n+1\choose i+1}A^iB^n\right)B & =AS(i)+\left(S(i+1)+A^i-{i+n+1\choose i+1}A^iB^n\right)B
 \end{split}\end{equation} \end{split}\end{equation}
行 178: 行 178:
 </​hidden>​ </​hidden>​
  
 +===== J. Random Walk =====
 +
 +==== 题意 ====
 +
 +给定 $n$ 个点,$m$ 条边,每条边两个权值 $(a_i,​b_i)$,在 $t$ 时刻经过第 $i$ 条边的收益为 $\max(\lfloor\frac {a_i}{2^t}\rfloor,​b)$,且一条边经过多次收益也计算多次。
 +
 +每个点一个点权 $w_i$,起点位于点 $i$ 的概率为 $\cfrac{w_i}{\sum_{i=1}^{n-1} w_i}$。每个时间单位人物从当前点等概率移动到相邻点,且移动到点 $n$ 后游戏结束。
 +
 +问人物的期望收益,然后接下来两种修改操作,每次修改后再次询问人物收益:
 +
 +  - 将某条边 $(u,v)$ 的边权修改为 $(a,​b)$,保证这条边原图中存在
 +  - 将某个点的 $w_i$ 修改
 +
 +数据保证 $1\le b_i\le a_i\le 100$,且第二类修改操作不超过 $n$ 个。
 +
 +==== 题解 ====
 +
 +设 $\text{dp}(u,​i)$ 表示 $t=i$ 时人物位于点 $u$ 的概率,$E(u)$ 表示人物经过点 $u$ 的期望次数,$G(u)$ 表示与 $u$ 相邻的边,$p(u)=\cfrac{w_i}{\sum_{i=1}^{n-1} w_i}$。
 +
 +不难发现 $t\ge 6$ 后每条边收益一定等于 $b_i$,于是答案等于
 +
 +$$
 +\sum_{u=1}^{n-1}\frac 1{\deg(u)}\sum_{e_i\in G(u)}\sum_{t=0}^{+\infty}\max(\lfloor\frac {a_i}{2^t}\rfloor,​b_i)\text{dp}(u,​t)=\sum_{u=1}^{n-1}\frac 1{\deg(u)}\sum_{e_i\in G(u)}\left(b_i\left(E(u)-\sum_{t=0}^5\text{dp}(u,​t)\right)+\sum_{t=0}^5\max (\lfloor\frac {a_i}{2^t}\rfloor,​b_i)\text{dp}(u,​t)\right)
 +$$
 +
 +关于 $\text{dp}(u,​t)(0\le t\le 5)$,可以 $O(6m)$ 暴力计算,接下来考虑计算 $E(u)$。
 +
 +考虑建立有向图,如果原图中边 $(u,v)$ 满足 $u,v\neq n$,则连边 $u\to v(w=\frac 1{\deg (u)}),v\to u(w=\frac 1{\deg (v)})$。
 +
 +否则,假设 $v=n$,则只连边 $u\to v(w=\frac 1{\deg (u)})$。同时建立超级源点 $s$,连边 $s\to u(w=p(u))$。
 +
 +对每个点 $u$,考虑所有入边 $v_1\to u,v_2\to u\cdots v_k\to u$,不难发现 $E(u)=\sum_{i=1}^k w(v_k\to u)E(v_k)$,初始条件 $E(s)=1$。
 +
 +于是上述方程可以表示成如下矩阵:
 +
 +$$
 +\left[ ​ \begin{array} ​ {c c c c | c}
 +1&​a_{1,​2}&​\cdots&​a_{1,​n-1}&​p(1)\\
 +a_{2,​1}&​1&​\cdots&​a_{2,​n-1}&​p(2)\\
 +\vdots&​\vdots&​\ddots&​\vdots\\
 +a_{n-1,​1}&​a_{n-1,​2}&​\cdots&​1&​p(n-1)\\
 +\end{array} ​ \right]
 +$$
 +
 +$O(n^3)$ 即可计算出所有 $E(u)$,因此计算初始答案复杂度为 $O(n^3+6m)$。
 +
 +接下来考虑修改操作,发现第一种修改操作对 $\text{dp}(u,​t),​E(u)$ 均无影响,如果 $u\neq n$,对答案影响为
 +
 +$$
 +\frac 1{\deg(u)}\left(b_i\left(E(u)-\sum_{t=0}^5\text{dp}(u,​t)\right)+\sum_{t=0}^5\max (\lfloor\frac {a_i}{2^t}\rfloor,​b_i)\text{dp}(u,​t)\right)
 +$$
 +
 +同理 $v\neq n$ 时也产生类似影响,因此单次处理复杂度 $O(6)$。
 +
 +第二种操作对 $\text{dp}(u,​t),​E(u)$ 均产生影响,同样 $\text{dp}(u,​t)$ 可以暴力计算,但 $E(u)$ 重新计算成本过高。
 +
 +注意到 $E(u)$ 的增广矩阵仅有增广部分被修改,因此可以预处理出原矩阵的逆 $A^{-1}$,则有
 +
 +$$
 +\begin{pmatrix}
 +E(1)\\
 +E(2)\\
 +\vdots\\
 +E(n-1)\\
 +\end{pmatrix}
 +=
 +A^{-1}
 +\begin{pmatrix}
 +p(1)\\
 +p(2)\\
 +\vdots\\
 +p(n-1)\\
 +\end{pmatrix}
 +$$
 +
 +因此可以 $O(n^2+6m)$ 重新计算一次答案。总时间复杂度 $O(n^3+6nm+6q)$。
 +
 +<hidden 查看代码>​
 +<code cpp>
 +const int MAXN=505,​MAXM=1e4+5,​MAXT=5,​mod=998244353;​
 +struct Edge{
 + int to,next;
 +}edge[MAXM<<​1];​
 +int head[MAXN],​edge_cnt;​
 +void Insert(int u,int v){
 + edge[++edge_cnt]=Edge{v,​head[u]};​
 + head[u]=edge_cnt;​
 +}
 +int w[MAXN],​deg[MAXN],​inv[MAXN];​
 +int a[MAXN][MAXN],​b[MAXN][MAXN],​c[MAXN][MAXN],​d[MAXN][MAXN],​E[MAXN];​
 +int dp[8][MAXN];​
 +int quick_pow(int n,int k){
 + int ans=1;
 + while(k){
 + if(k&​1)ans=1LL*ans*n%mod;​
 + n=1LL*n*n%mod;​
 + k>>​=1;​
 + }
 + return ans;
 +}
 +void calc1(int n){
 + static int temp[MAXN][MAXN<<​1];​
 + n--;
 + _rep(i,​1,​n){
 + _rep(j,​1,​n){
 + if(c[i][j])
 + temp[i][j]=mod-inv[deg[j]];​
 + else
 + temp[i][j]=0;​
 + }
 + temp[i][i]=1;​
 + temp[i][i+n]=1;​
 + }
 + _rep(i,​1,​n){
 + int pos=-1;
 + _rep(j,​i,​n){
 + if(temp[j][i]){
 + pos=j;
 + break;
 + }
 + }
 + if(pos!=i)swap(temp[i],​temp[pos]);​
 + int div=quick_pow(temp[i][i],​mod-2);​
 + for(int j=n*2;​j>​=i;​j--)
 + temp[i][j]=1LL*temp[i][j]*div%mod;​
 + _rep(j,​1,​n){
 + if(j==i)continue;​
 + for(int k=n*2;​k>​=i;​k--)
 + temp[j][k]=(temp[j][k]-1LL*temp[j][i]*temp[i][k])%mod;​
 + }
 + }
 + _rep(i,​1,​n)_rep(j,​1,​n)
 + d[i][j]=(temp[i][j+n]+mod)%mod;​
 +}
 +void add_edge(int u,int v,int &ans){
 + _rep(t,​0,​MAXT)
 + ans=(ans+1LL*dp[t][u]*inv[deg[u]]%mod*max(a[u][v]>>​t,​b[u][v]))%mod;​
 + ans=(ans+1LL*E[u]*inv[deg[u]]%mod*b[u][v])%mod;​
 +}
 +void del_edge(int u,int v,int &ans){
 + _rep(t,​0,​MAXT)
 + ans=(ans-1LL*dp[t][u]*inv[deg[u]]%mod*max(a[u][v]>>​t,​b[u][v]))%mod;​
 + ans=(ans-1LL*E[u]*inv[deg[u]]%mod*b[u][v])%mod;​
 + ans=(ans+mod)%mod;​
 +}
 +int calc2(int n){
 + int ans=0,s=0;
 + mem(dp,0);
 + n--;
 + _rep(i,​1,​n)s+=w[i];​
 + s=quick_pow(s,​mod-2);​
 + _rep(i,​1,​n){
 + dp[0][i]=1LL*w[i]*s%mod;​
 + E[i]=0;
 + _rep(j,​1,​n)
 + E[i]=(E[i]+1LL*w[j]*d[i][j])%mod;​
 + E[i]=1LL*E[i]*s%mod;​
 + E[i]=(E[i]+mod-dp[0][i])%mod;​
 + }
 + _rep(t,​1,​MAXT){
 + _rep(u,​1,​n){
 + for(int i=head[u];​i;​i=edge[i].next){
 + int v=edge[i].to;​
 + dp[t][v]=(dp[t][v]+1LL*dp[t-1][u]*inv[deg[u]])%mod;​
 + }
 + }
 + _rep(u,​1,​n)
 + E[u]=(E[u]+mod-dp[t][u])%mod;​
 + }
 + _rep(u,​1,​n){
 + for(int i=head[u];​i;​i=edge[i].next){
 + int v=edge[i].to;​
 + add_edge(u,​v,​ans);​
 + }
 + }
 + return ans;
 +}
 +int main(){
 + int n=read_int(),​m=read_int(),​q=read_int();​
 + _for(i,​1,​n)
 + w[i]=read_int();​
 + while(m--){
 + int u=read_int(),​v=read_int();​
 + a[u][v]=a[v][u]=read_int();​
 + b[u][v]=b[v][u]=read_int();​
 + c[u][v]=c[v][u]=1;​
 + Insert(u,​v);​Insert(v,​u);​
 + deg[u]++;​deg[v]++;​
 + }
 + inv[1]=1;
 + _rep(i,​2,​n)
 + inv[i]=1LL*(mod-mod/​i)*inv[mod%i]%mod;​
 + calc1(n);
 + int ans=calc2(n);​
 + enter(ans);​
 + while(q--){
 + int opt=read_int();​
 + if(opt==1){
 + int u=read_int(),​v=read_int();​
 + if(u>​v)swap(u,​v);​
 + del_edge(u,​v,​ans);​
 + if(v!=n)del_edge(v,​u,​ans);​
 + a[u][v]=a[v][u]=read_int();​
 + b[u][v]=b[v][u]=read_int();​
 + add_edge(u,​v,​ans);​
 + if(v!=n)add_edge(v,​u,​ans);​
 + }
 + else{
 + int u=read_int();​
 + w[u]=read_int();​
 + ans=calc2(n);​
 + }
 + enter(ans);​
 + }
 + return 0;
 +}
 +</​code>​
 +</​hidden>​
2020-2021/teams/legal_string/组队训练比赛记录/contest17.1630330525.txt.gz · 最后更改: 2021/08/30 21:35 由 jxm2001