走迷宫

Morenan被困在了一个迷宫里。迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T。可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点。这样,Morenan走的步数可能很长,也可能是无限,更可能到不了终点。若到不了终点,则步数视为无穷大。但你必须想方设法求出Morenan所走步数的期望值。

N<=10000,M<=1000000,保证强连通分量的大小不超过100

Clove_unique的题解

首先考虑图是一个DAG的情况

如果除了终点之外还有出度为0的点,那么答案为INF。因为有概率不走到终点,无穷级数里面有∞。

然后令f(i)表示从点i走到终点的期望步数,那么f(i)=∑(i,v)∈E(f(v)+1)、∗out(i),其中out(i)从点i走一条边的概率(也就是出度的倒数)。

如果图不是一个DAG的话,可以缩点之后将图变成一个DAG,对于DAG上的边直接dp,但是强连通分量里的点可以互相到达,这实际上就是列出了一些方程然后高斯消元。

CO LD inf=1e18,eps=1e-12;
CO int N=10000+10,M=100+10;
vector<int> to[N],rto[N];
LD out[N];
int pos[N],dfn,low[N];
int stk[N],top,ins[N];
int bln[N],idx;
vector<int> scc[N]; void tarjan(int u){
pos[u]=low[u]=++dfn;
stk[++top]=u,ins[u]=1;
for(int i=0;i<(int)to[u].size();++i){
int v=to[u][i];
if(!pos[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]) low[u]=min(low[u],pos[v]);
}
if(low[u]==pos[u]){
++idx;
int x;
do{
x=stk[top--],ins[x]=0;
bln[x]=idx,scc[idx].push_back(x);
}while(x!=u);
}
} bool vis[N]; void dfs(int u){
vis[u]=1;
for(int i=0;i<(int)to[u].size();++i){
int v=to[u][i];
if(!vis[v]) dfs(v);
}
} int in[N],tmp[N];
LD f[N],a[M][M]; void gauss(int n){
for(int i=1;i<=n;++i){
int p=i;
for(int j=i+1;j<=n;++j)
if(abs(a[j][i])>abs(a[p][i])) p=j;
if(p!=i) swap(a[p],a[i]);
for(int j=1;j<=n;++j)if(j!=i and abs(a[j][i])>eps){
double coef=-a[j][i]/a[i][i];
for(int k=i;k<=n+1;++k) a[j][k]+=coef*a[i][k];
}
}
for(int i=1;i<=n;++i) a[i][n+1]/=a[i][i],a[i][i]=1;
} int main(){
int n=read<int>(),m=read<int>(),s=read<int>(),t=read<int>();
while(m--){
int u=read<int>(),v=read<int>();
to[u].push_back(v),rto[v].push_back(u);
++out[u];
}
for(int i=1;i<=n;++i) out[i]=1/out[i];
for(int i=1;i<=n;++i)
if(!pos[i]) tarjan(i);
dfs(s);
if(!vis[t]){
puts("INF");
return 0;
}
for(int u=1;u<=n;++u)
for(int i=0;i<(int)rto[u].size();++i){
int v=rto[u][i];
if(bln[u]!=bln[v]) ++in[bln[v]];
}
for(int i=1;i<=idx;++i)if(i!=bln[t])
if(!in[i]){
puts("INF");
return 0;
}
deque<int> Q(1,bln[t]);
while(Q.size()){
int x=Q.front();Q.pop_front();
memset(a,0,sizeof a);
int num=scc[x].size();
// cerr<<"scc="<<endl;
// for(int i=1;i<=num;++i) cerr<<" "<<scc[x][i-1];
// cerr<<endl;
for(int i=1;i<=num;++i) tmp[scc[x][i-1]]=i;
for(int i=1;i<=num;++i){
int u=scc[x][i-1];
a[i][i]=1,a[i][num+1]=f[u];
if(u==t) continue;
for(int j=0;j<(int)to[u].size();++j){
int v=to[u][j];
if(bln[v]!=bln[u]) continue;
a[i][tmp[v]]-=out[u],a[i][num+1]+=out[u];
}
}
gauss(num);
for(int i=1;i<=num;++i){
int u=scc[x][i-1];
f[u]=a[i][num+1];
for(int j=0;j<(int)rto[u].size();++j){
int v=rto[u][j];
if(bln[v]!=x){
if(--in[bln[v]]==0) Q.push_back(bln[v]);
f[v]+=(f[u]+1)*out[v];
}
}
}
}
printf("%.3Lf\n",f[s]);
return 0;
}

Fox Rocks

Mr. Fox sure loves his rocks! In fact, when he's not in a hurry, he often looks at the rocks lying around near him to decide where to wander in his forest.

Mr. Fox lives in a forest with \(N\) clearings, numbered from \(0\) to \(N-1\), with \(P\) one-way trails initially running amongst them. The \(i\)th trail runs from clearing \(A_i\) to a different clearing \(B_i\), and is littered with \(R_i\) rocks. No two clearings are connected by multiple trails running in the same direction, though they could be connected by 2 trails running in opposite directions. Additionally, an interesting property of this forest is that a trail from clearing \(a\) to clearing \(b\) may only exist if \(0 ≤ \lfloor\frac{b}{4}\rfloor - \lfloor\frac{a}{4}\rfloor ≤ 1\).

To entertain himself over a period of \(D\) days, Mr. Fox will cause one event to occur on each day. The \(i\)th event may be one of 3 types, determined by the value of \(E_i\):

  1. Given 3 integers \(X_i, Y_i\), and \(Z_i\), Mr. Fox will create a new trail from clearing \(X_i\) to a different clearing \(Y_i\), and drop \(Z_i\) rocks onto it. It's guaranteed that no trail from \(X_i\) to \(Y_i\) will exist at the start of the \(i\)th day, and that \(0 ≤ \lfloor\frac{X_i}{4}\rfloor - \lfloor\frac{Y_i}{4}\rfloor ≤ 1\) will hold.

  2. Given 2 distinct integers \(X_i\) and \(Y_i\), Mr. Fox will completely destroy the trail from clearing \(X_i\) to clearing \(Y_i\) (which is guaranteed to exist at the start of the \(i\)th day). Note that, once such a trail is destroyed, a new trail from \(X_i\) to \(Y_i\) may be created in the future.

  3. Given 2 distinct integers \(X_i\) and \(Y_i\), Mr. Fox will take a "random stroll" starting at clearing \(X_i\), and would like to determine the probability that he'll visit clearing \(Y_i\) at least once during it.

A "random stroll" consists of repeating the following process potentially infinitely: If Mr. Fox is currently in some clearing \(c\), and there are no outgoing trails from \(c\), then the stroll ends immediately. Otherwise, he'll consider all of the rocks on all of the outgoing trails from \(c\), choose one of these rocks uniformly at random, follow the trail on which that rock lies to its destination clearing (without removing any rocks), and repeat the process from his new clearing.

For each event of type 3, output the requested probability.

\(1 ≤ T ≤ 20, 1 ≤ N ≤ 50,000, 0 ≤ P ≤ 100,000, 1 ≤ D ≤ 20,000\)

题解

性质分析

首先把算概率转化成算经过次数的期望。每个点的期望定义式是

\[E_u=\sum_{v\neq T}P_{v,u}E_v+[u=S]
\]

把题目所给的DAG套SCC的图按除以 \(4\) 下取整分块,显然每个点的期望只可能与到它有边的前一块或同一块的点有关。该如何利用这一性质呢?

考虑暴力的做法。我们先对起点所在的块进行解方程,算出块内每一个点的期望。然后把它们的期望看成常数,用它们的期望去更新下一块内点的期望方程的常数项。接着对下一块进行同样的操作即可。

现在我们要加速这一递推的过程。注意到一段连续块内期望的转移只与连边情况有关,在没有修改的情况下是固定的。

算法设计

我们可以使用主元法,把连续段头的那一块里的点的期望看成未知变量,将连续段尾的那一块里的每个点的期望用这些未知变量表示出来。这样合并两连续块段 \([l,mid],[mid+1,r]\) 的时候只需要把第 \(mid+1\) 块设的未知变量用第 \(l\) 块设的位置变量解出来,并带入第 \(r\) 块的系数向量,即可将第 \(r\) 块里的点的期望用第 \(l\) 块里点的期望表示出来。

用线段树来维护这个快速递推。询问的时候只需要把起点所在块内每个点的期望解出来,然后用线段树快速递推到终点所在块的前一块,最后暴力递推终点所在块的期望即可。

细节处理

考虑下面这组数据:

1
4 4 1
0 1 1
0 3 1
1 2 1
2 1 1
3 0 3

现在要算从 \(0\) 号节点出发走到 \(3\) 号节点的概率,显然它是 \(0.5\)。

但是我的程序会输出nan,这是因为 \(1,2\) 号节点的期望其实是 \(\infty\),然后高斯消元就会出现某主元找不到系数非 \(0\) 行等等问题。

我的解决方法是额外维护每个点能不能直接或间接的走到下一块中去,如果不能的话直接钦定它的期望为 \(0\)。因为它不会对后面的点有贡献,所以这样做没有问题。

时间复杂度 \(O(64m\log \lfloor\frac{n}{4}\rfloor)\)。

struct node{LD v[4];};
node operator*(node a,LD k){
for(int i=0;i<=3;++i) a.v[i]*=k;
return a;
}
node operator/(node a,LD k){
for(int i=0;i<=3;++i) a.v[i]/=k;
return a;
}
node operator+(node a,CO node&b){
for(int i=0;i<=3;++i) a.v[i]+=b.v[i];
return a;
} CO int N=50000+10;
LD edge[N][2][4],out[N]; namespace T{
int vis[N];
node coef[N][4];
LD a[4][4];node b[4]; #define lc (x<<1)
#define rc (x<<1|1)
void dfs(int u){ // search valid points
if(vis[u]) return;
vis[u]=1;
for(int i=0;i<=3;++i)if(edge[u][0][i]) dfs(4*(u/4)+i);
}
void push_up(int x,int l,int r){
int mid=(l+r)>>1; memset(a,0,sizeof a),memset(b,0,sizeof b);
for(int i=0;i<=3;++i)if(vis[4*(mid+1)+i]) // mid+1
for(int j=0;j<=3;++j)if(edge[4*(mid+1)+i][1][j]) // mid
b[i]=b[i]+coef[lc][j]*edge[4*(mid+1)+i][1][j]/out[4*mid+j];
for(int i=0;i<=3;++i){
a[i][i]=1;
if(!vis[4*(mid+1)+i]) continue;
for(int j=0;j<=3;++j)if(edge[4*(mid+1)+i][0][j])
a[i][j]-=edge[4*(mid+1)+i][0][j]/out[4*(mid+1)+j];
} for(int i=0;i<=3;++i){
int p=i;
for(int j=i+1;j<=3;++j)
if(abs(a[j][i])>abs(a[p][i])) p=j;
if(p!=i) swap(a[p],a[i]),swap(b[p],b[i]);
for(int j=0;j<=3;++j)if(j!=i){
b[j]=b[j]+b[i]*-a[j][i]/a[i][i]; // edit 4: gauss precision
for(int k=3;k>=i;--k) a[j][k]+=a[i][k]*-a[j][i]/a[i][i];
}
}
for(int i=0;i<=3;++i) b[i]=b[i]/a[i][i],a[i][i]=1; memset(coef[x],0,sizeof coef[x]);
for(int i=0;i<=3;++i)if(vis[4*r+i])
for(int j=0;j<=3;++j)if(vis[4*(mid+1)+j])
coef[x][i]=coef[x][i]+b[j]*coef[rc][i].v[j];
}
void build(int x,int l,int r){
if(l==r){
memset(vis+4*l,0,4*sizeof(int));
for(int i=0;i<=3;++i)for(int j=0;j<=3;++j)
if(edge[4*(l+1)+i][1][j]) dfs(4*l+j);
memset(coef[x],0,sizeof coef[x]);
for(int i=0;i<=3;++i) coef[x][i].v[i]=vis[4*l+i]?1:0;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
push_up(x,l,r);
}
void change(int x,int l,int r,int p){
if(l==r){
memset(vis+4*l,0,4*sizeof(int));
for(int i=0;i<=3;++i)for(int j=0;j<=3;++j)
if(edge[4*(l+1)+i][1][j]) dfs(4*l+j);
memset(coef[x],0,sizeof coef[x]);
for(int i=0;i<=3;++i) coef[x][i].v[i]=vis[4*l+i]?1:0;
return;
}
int mid=(l+r)>>1;
if(p<=mid) change(lc,l,mid,p);
else change(rc,mid+1,r,p);
push_up(x,l,r);
}
vector<node> query(int x,int l,int r,int ql,int qr){
if(ql<=l and r<=qr) return vector<node>(coef[x],coef[x]+4);
int mid=(l+r)>>1;
if(qr<=mid) return query(lc,l,mid,ql,qr);
if(ql>mid) return query(rc,mid+1,r,ql,qr);
vector<node> left=query(lc,l,mid,ql,mid),
right=query(rc,mid+1,r,mid+1,qr); // edit 3: ql,qr memset(a,0,16*sizeof(LD)),memset(b,0,sizeof b);
for(int i=0;i<=3;++i)if(vis[4*(mid+1)+i]) // mid+1
for(int j=0;j<=3;++j)if(edge[4*(mid+1)+i][1][j]) // mid
b[i]=b[i]+left[j]*edge[4*(mid+1)+i][1][j]/out[4*mid+j];
for(int i=0;i<=3;++i){
a[i][i]=1;
if(!vis[4*(mid+1)+i]) continue;
for(int j=0;j<=3;++j)if(edge[4*(mid+1)+i][0][j])
a[i][j]-=edge[4*(mid+1)+i][0][j]/out[4*(mid+1)+j];
} for(int i=0;i<=3;++i){
int p=i;
for(int j=i+1;j<=3;++j)
if(abs(a[j][i])>abs(a[p][i])) p=j;
if(p!=i) swap(a[p],a[i]),swap(b[p],b[i]);
for(int j=0;j<=3;++j)if(j!=i){
b[j]=b[j]+b[i]*-a[j][i]/a[i][i];
for(int k=3;k>=i;--k) a[j][k]+=a[i][k]*-a[j][i]/a[i][i];
}
}
for(int i=0;i<=3;++i) b[i]=b[i]/a[i][i],a[i][i]=1;
vector<node> ans(4);
for(int i=0;i<=3;++i)if(vis[4*qr+i]) // edit 2: qr
for(int j=0;j<=3;++j)if(vis[4*(mid+1)+j])
ans[i]=ans[i]+b[j]*right[i].v[j];
return ans;
}
#undef lc
#undef rc
} int vis[N];
LD a[4][5],b[4]; void dfs(int u){ // search valid points
if(vis[u]) return;
vis[u]=1;
for(int i=0;i<=3;++i)if(edge[u][0][i]) dfs(4*(u/4)+i);
}
void real_main(int cas){
if(cas>1) puts("");
printf("Case #%d: ",cas); int n=read<int>(),m=read<int>(),q=read<int>();
n+=4-n%4;
memset(edge,0,(n+4)*8*sizeof(LD)),memset(out,0,(n+4)*sizeof(LD)); // edit 5: init
while(m--){
int u=read<int>(),v=read<int>(),w=read<int>();
edge[v][v/4>u/4][u%4]=w,out[u]+=w;
} T::build(1,0,n/4-1);
while(q--){
int opt=read<int>();
if(opt==1){
int u=read<int>(),v=read<int>(),w=read<int>();
edge[v][v/4>u/4][u%4]=w,out[u]+=w;
T::change(1,0,n/4-1,u/4);
}
else if(opt==2){
int u=read<int>(),v=read<int>();
out[u]-=edge[v][v/4>u/4][u%4],edge[v][v/4>u/4][u%4]=0;
T::change(1,0,n/4-1,u/4);
}
else{
int u=read<int>(),v=read<int>();
if(u/4>v/4){
printf("0.000000 ");
continue;
} if(u/4==v/4){
memset(vis+4*(u/4),0,4*sizeof(int));
dfs(v);
for(int i=0;i<=3;++i)for(int j=0;j<=3;++j)
if(edge[4*(u/4+1)+i][1][j]) dfs(4*(u/4)+j); memset(a,0,20*sizeof(LD)),a[u%4][4]=1;
for(int i=0;i<=3;++i){
a[i][i]=1;
if(!vis[4*(u/4)+i]) continue; // edit 1: T's vis
for(int j=0;j<=3;++j)if(j!=v%4 and edge[4*(u/4)+i][0][j])
a[i][j]-=edge[4*(u/4)+i][0][j]/out[4*(u/4)+j];
} for(int i=0;i<=3;++i){
int p=i;
for(int j=i+1;j<=3;++j)
if(abs(a[j][i])>abs(a[p][i])) p=j;
if(p!=i) swap(a[p],a[i]);
for(int j=0;j<=3;++j)if(j!=i){
LD c=-a[j][i]/a[i][i];
for(int k=i;k<=4;++k) a[j][k]+=a[i][k]*c;
}
}
printf("%.6Lf ",a[v%4][4]/a[v%4][v%4]);
continue;
} memset(a,0,sizeof a),a[u%4][4]=1;
for(int i=0;i<=3;++i){
a[i][i]=1;
if(!T::vis[4*(u/4)+i]) continue;
for(int j=0;j<=3;++j)if(edge[4*(u/4)+i][0][j])
a[i][j]-=edge[4*(u/4)+i][0][j]/out[4*(u/4)+j];
} for(int i=0;i<=3;++i){
int p=i;
for(int j=i+1;j<=3;++j)
if(abs(a[j][i])>abs(a[p][i])) p=j;
if(p!=i) swap(a[p],a[i]);
for(int j=0;j<=3;++j)if(j!=i)
for(int k=4;k>=i;--k) a[j][k]+=a[i][k]*-a[j][i]/a[i][i];
}
for(int i=0;i<=3;++i) a[i][4]/=a[i][i],a[i][i]=1;
vector<node> mid=T::query(1,0,n/4-1,u/4,v/4-1);
memset(b,0,4*sizeof(LD));
for(int i=0;i<=3;++i)if(T::vis[4*(v/4-1)+i])
for(int j=0;j<=3;++j)if(T::vis[4*(u/4)+j])
b[i]+=a[j][4]*mid[i].v[j];
memset(vis+4*(v/4),0,4*sizeof(int));
dfs(v);
for(int i=0;i<=3;++i)for(int j=0;j<=3;++j)
if(edge[4*(v/4+1)+i][1][j]) dfs(4*(v/4)+j); memset(a,0,20*sizeof(LD));
for(int i=0;i<=3;++i)
for(int j=0;j<=3;++j)if(edge[4*(v/4)+i][1][j])
a[i][4]+=b[j]*edge[4*(v/4)+i][1][j]/out[4*(v/4-1)+j];
for(int i=0;i<=3;++i){
a[i][i]=1;
if(!vis[4*(v/4)+i]) continue;
for(int j=0;j<=3;++j)if(j!=v%4 and edge[4*(v/4)+i][0][j])
a[i][j]-=edge[4*(v/4)+i][0][j]/out[4*(v/4)+j];
} for(int i=0;i<=3;++i){
int p=i;
for(int j=i+1;j<=3;++j)
if(abs(a[j][i])>abs(a[p][i])) p=j;
if(p!=i) swap(a[p],a[i]);
for(int j=0;j<=3;++j)if(j!=i)
for(int k=4;k>=i;--k) a[j][k]+=a[i][k]*-a[j][i]/a[i][i];
}
printf("%.6Lf ",a[v%4][4]/a[v%4][v%4]);
}
}
}
int main(){
// freopen("Gym.in","r",stdin),freopen("Gym.out","w",stdout);
int T=read<int>();
for(int i=1;i<=T;++i) real_main(i);
return 0;
}

一些代码调试杂谈:

  • 这道题的线段树合并实在太复杂,以至于我必须把push_upquery的合并分开单独实现。我以前写的线段树询问递归的时候直接传的ql,qr,在这道题里面就吃了大亏。以后要换成现在这种实现方式了。

  • 高斯消元的不同写法有精度问题,解决方法是尽量不用中间变量,先乘后除。

  • 为了方便实现我把n补齐到了4的倍数。由于算vis的时候需要用到下一块的反向边,所以初始化的时候需要把前n+4个位置清空了。(造数据的能把我这个卡掉,真是佩服。)

鉴于这题的小样例怎么写都能过,没有数据给你调,所以需要自己写对拍。暴力程序:

CO int N=100+10;
int n;
int edge[N][N],out[N];
int vis[N];
LD arr[N][N]; void dfs(int u){
if(vis[u]) return;
vis[u]=1;
for(int v=0;v<n;++v)if(edge[v][u]) dfs(v);
}
void real_main(int cas){
if(cas>1) puts("");
printf("Case #%d: ",cas); read(n);
int m=read<int>(),q=read<int>();
memset(edge,0,sizeof edge),memset(out,0,sizeof out);
while(m--){
int u=read<int>(),v=read<int>(),w=read<int>();
edge[u][v]=w,out[u]+=w;
} while(q--){
int opt=read<int>();
if(opt==1){
int u=read<int>(),v=read<int>(),w=read<int>();
edge[u][v]=w,out[u]+=w;
}
else if(opt==2){
int u=read<int>(),v=read<int>();
out[u]-=edge[u][v],edge[u][v]=0;
}
else{
int u=read<int>(),v=read<int>();
memset(vis,0,sizeof vis);
dfs(v); memset(arr,0,sizeof arr),arr[u][n]=1;
for(int i=0;i<n;++i){
arr[i][i]=1;
if(!vis[i]) continue;
for(int j=0;j<n;++j)if(edge[j][i] and j!=v)
arr[i][j]-=(LD)edge[j][i]/out[j];
}
for(int i=0;i<n;++i){
int p=i;
for(int j=i+1;j<n;++j)
if(abs(arr[j][i])>abs(arr[p][i])) p=j;
if(p!=i) swap(arr[p],arr[i]);
for(int j=0;j<n;++j)if(j!=i)
for(int k=n;k>=i;--k) arr[j][k]+=arr[i][k]*-arr[j][i]/arr[i][i];
}
printf("%.6Lf ",arr[v][n]/arr[v][v]);
}
}
}
int main(){
// freopen("Gym.in","r",stdin),freopen("Gbf.out","w",stdout);
int T=read<int>();
for(int i=1;i<=T;++i) real_main(i);
return 0;
}

这题算是刷新了我对高斯消元的认知。

SDOI2012 走迷宫的更多相关文章

  1. BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )

    数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了. E(u) = 1 + Σ E(v) / degree(u) 对拍时发现网上2个程序的INF判断和我不一 ...

  2. BZOJ 2707: [SDOI2012]走迷宫 [高斯消元 scc缩点]

    2707: [SDOI2012]走迷宫 题意:求s走到t期望步数,\(n \le 10^4\),保证\(|SCC| \le 100\) 求scc缩点,每个scc高斯消元,scc之间直接DP 注意每次清 ...

  3. 【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望

    [BZOJ2707][SDOI2012]走迷宫 Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,M ...

  4. bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)

    Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿 ...

  5. BZOJ2707 [SDOI2012]走迷宫 【概率dp + tarjan + 高斯消元】

    题目 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的 ...

  6. [SDOI2012]走迷宫 (强连通分量缩点,动态规划,高斯消元)

    题面 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的 ...

  7. bzoj2702[SDOI2012]走迷宫

    题意:给你一个有向图,点数10000,边数1000000,SCC大小不超过100(按数据范围的写法只有第三部分数据满足这个条件,不过第二部分数据并没有出现大小大于100个点的SCC,我是用数组大小为1 ...

  8. BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)

    题目链接 一个点到达终点的期望步数 \(E_i=\sum_{(i,j)\in G}\frac{E_j+1}{out[i]}\),\(out[i]\)为点\(i\)的出度. 那么对于一个DAG可以直接在 ...

  9. BZOJ2707: [SDOI2012]走迷宫(期望 tarjan 高斯消元)

    题意 题目链接 Sol 设\(f[i]\)表示从\(i\)走到\(T\)的期望步数 显然有\(f[x] = \sum_{y} \frac{f[y]}{deg[x]} + 1\) 证明可以用全期望公式. ...

随机推荐

  1. js密码加密

    1.base64加密:在页面中引入base64.js文件,调用方法为: <!DOCTYPE HTML> <html> <head> <meta charset ...

  2. 高系统的分布性有状态的中间层Actor模型

    写在前面 https://www.cnblogs.com/gengzhe/p/ray_actor.html Orleans是基于Actor模型思想的.NET领域的框架,它提供了一种直接而简单的方法来构 ...

  3. TRex,一个基于DPDK的数据包发生器,测试仪

    1. introduction TRex是cisco基于Intel dpdk开发的软件程序.推荐在CentOS/RHEL 7.6, 64bits中运行,否则connectx-4网卡不可使用. 笔者在U ...

  4. kali无法安装nvidia显卡驱动

    按照各位大神的博客安装nvidia显卡驱动一直失败,重启之后无法正常进入系统,恢复模式可以进入,一直以为自己是不是哪里步骤不对,后面来回重装了几次系统. 最后意识到虚拟机里用的是虚拟网卡,并非宿主机的 ...

  5. AKKA HTTP 简单示例

    AKKA HTTP 简单示例 依赖包: compile("com.typesafe.akka:akka-http_2.13:10.1.8") compile("com.t ...

  6. SSL密钥协商过程分析

    一.说明 尽管做过证书生成.双向认证.SSL通信编程等事情,但一直不清楚SSL如何完成密钥交换.看网上的资料则众说纷纭,最近和朋友学习时聊到了这个问题,然后正巧上周处理客户反馈SSL版本过低时领导也想 ...

  7. git cherry-pick 命令,解决冲突后没有 commit 变更,再次pull 时出错

    Git : You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists). 解决方法:(1)使用git status 命令查看当前 ...

  8. 第十六节:Asp.Net Core中Session的使用、扩展、进程外Session

    一. 简介 关于Session的原理可参照Asp.Net版本Session的文章,去查阅. 1. 普通用法 (1).通过Nuget引入[Microsoft.AspNetCore.Http]程序集,Co ...

  9. docker搭建etcd集群环境

    其实关于集群网上说的方案已经很多了,尤其是官网,只是这里我个人只有一个虚拟机,在开发环境下建议用docker-compose来搭建etcd集群. 1.拉取etcd镜像 docker pull quay ...

  10. [转] js async await 终极异步解决方案

    阅读目录 回顾 Promise async await 字面理解 async.await 如何执行 await 操作符 总结 既然有了promise 为什么还要有async await ? 当然是pr ...