Apple - 高斯消元 - 概率与期望

题目大意:有两个变量x,y初始为0,每次x=(x+1)%n或者y=(y+1)%m。问第一次变成x=X,y=Y时的期望步数。 n , m ≤ 100 n,m\le100 n,m100
题解:显然直接列方程高消,可以将(n-1,m-1)看作0求(n-1-X,m-1-Y)的答案。注意到可以只设最后一行或者最后一行一列求解。不过后者好实现一点,所以场上写了这个。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define db long double
using namespace std;const int N=410;db a[N][N],b[N];
inline db gabs(db x) { return x<0?-x:x; }
inline int gauss(int n)
{
    rep(i,1,n)
    {
        int x=i;rep(j,i,n) if(gabs(a[j][i])>gabs(a[x][i])) x=j;
        if(i^x) swap(a[i],a[x]),swap(b[i],b[x]);
        b[i]/=a[i][i];for(int j=n;j>=i;j--) a[i][j]/=a[i][i];
        rep(j,1,n) if(i^j)
        {
            b[j]-=a[j][i]*b[i];
            for(int k=n;k>=i;k--) a[j][k]-=a[j][i]*a[i][k];
        }
    }
    return 0;
}
namespace subtask123{
    const int N=25;int P[N][N];
    inline int brute_force65(int n,int m,int X,int Y)
    {
        int cnt=0,fcc=0;
        rep(i,0,n-1) rep(j,0,m-1) P[i][j]=++cnt;
        rep(i,0,n-1) rep(j,0,m-1)
        {
            int x=P[i][j],y=P[(i+1)%n][j],z=P[i][(j+1)%m];
            if(i==X&&j==Y) { fcc++,a[fcc][x]=1;continue; }
            b[++fcc]=2,a[fcc][x]=2,a[fcc][y]=a[fcc][z]=-1;
        }
        return gauss(cnt),!printf("%.6lf\n",(double)b[P[0][0]]);
    }
}
namespace subtask45{
    const int N=210;int P[N],Q[N],fcc;
    namespace BS_space{
        const int N=210;int n;
        struct BS{
            db a[N];inline int set(int x,db v) { rep(i,0,n) a[i]=0;return a[x]=v,0; }
            inline BS operator+(const BS &bs)const { BS res;res=*this;rep(i,0,n) res.a[i]+=bs.a[i];return res; }
            inline BS operator*(db x)const { BS res;res=*this;rep(i,0,n) res.a[i]*=x;return res; }
            inline BS operator+(db x)const { BS res;res=*this;res.a[0]+=x;return res; }
        };
    }using BS_space::BS;BS bs[N][N];
    inline int add_fc(int x,int y,const BS &bs,int n) { b[++fcc]=2+bs.a[0],a[fcc][x]=2,a[fcc][y]=-1;rep(i,1,n) a[fcc][i]-=bs.a[i];return 0; }
    inline db calc(const BS &bs,int n) { db res=bs.a[0];rep(i,1,n) res+=bs.a[i]*b[i];return res; }
    inline int acceptable_solution(int n,int m,int X,int Y)
    {
        BS_space::n=n+m-1;int cnt=0;
        rep(i,0,m-2) bs[n-1][i].set(P[i]=++cnt,1);
        rep(i,0,n-2) bs[i][m-1].set(Q[i]=++cnt,1);
        a[fcc=1][P[m-1]=Q[n-1]=++cnt]=1,b[fcc]=0;
        for(int i=n-2;i>=0;i--) for(int j=m-2;j>=0;j--)
            bs[i][j]=(bs[i+1][j]+bs[i][j+1])*0.5+1;
        rep(i,0,m-2) add_fc(P[i],P[i+1],bs[0][i],cnt);
        rep(i,0,n-2) add_fc(Q[i],Q[i+1],bs[i][0],cnt);
        return gauss(cnt),!printf("%.6lf\n",(double)calc(bs[n-1-X][m-1-Y],cnt));
    }
}
int main()
{
    int n,m,x,y;scanf("%d%d%d%d",&n,&m,&x,&y);
    x%=n,y%=m;if(n>m) swap(n,m),swap(x,y);
    if(x==0&&y==0) return !printf("0.000000\n");
    if(n==1) return !printf("%.6lf\n",2*double(y));
    if(max(n,m)<=10) return subtask123::brute_force65(n,m,x,y);
    return subtask45::acceptable_solution(n,m,x,y);
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值