[集训队联考]Dream

这里写图片描述
这里写图片描述

题解。

假如设 Fi F i 表示从i走到终点的答案,那么对于不同的时间,难以将参数T分离。
于是,假如我们可以计算 Gi G i 表示点i的期望经过次数,一条边(x,y)的贡献就是 GxP(x,y)Len G x ⋅ P ( x , y ) ⋅ L e n ,那么就可以根据边的p分成两部分,统计左右的一次项系数与常数就可以了。
对于每一个起点,发现计算 Gi G i 的过程都是类似的,唯一不同的是起点S G G 的方程中要加一。
再设Ck,若S是起点则 Cs=1 C s = 1 否则 Cs=0 C s = 0 ,通过高斯消元解出 Gi=aiCi G i = ∑ a i ⋅ C i
接下来就是离线询问,简单统计了。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define abs(x) ((x)>0?(x):-(x))
using namespace std;
typedef long long ll;
const ll mo = 1e9 + 7, N = 410, M = 1e5+10;
ll f[N][2*N],n,m,q;
ll wsum[N],inv[N];
ll T,X;
ll bz[N],sg[N];
pair<int,pair<int,int> > qu[2000100];

ll ksm(ll x,ll y) {
    ll ret = 1; for (;y;y>>=1) {
        if (y & 1) ret = ret * x % mo;
        x = x * x % mo;
    } return ret;
}

struct edge{
    ll x,y,S,C,P,Po;
    bool operator < (const edge &b) const{
        return P < b.P;
    }
} e[M];

void gauss() {
    for (int i = 1; i <= n; i++) f[i][i] = -1, f[i][i+n] = 1;
    for (int i = 1; i <= m; i++) {
        int x = e[i].x, y = e[i].y;
        f[y][x] = (f[y][x] + e[i].Po) % mo;
    }

    for (int i = 1; i <= n; i++) {
        int fd = 0; for (int j = 1; j <= n; j++) 
            if (!bz[j] && f[j][i]) {
                sg[i] = j, bz[j] = 1, fd = j; break;
            }
        for (int j = 1; j <= n; j++) if (!bz[j] && f[j][i]) {
            ll a = f[fd][i],b = f[j][i];
            for (int z = 0; z <= 2 * n; z++) 
                f[j][z] = (f[j][z] * a - f[fd][z] * b) % mo;
        }
    }

    for (int i = n; i; i--) {
        int fd = sg[i], inv = ksm(f[fd][i],mo-2);
        f[fd][i] = f[fd][i] * inv % mo;
        for (int j = n+1; j <= n*2; j++) 
            f[fd][j] = f[fd][j] * inv % mo;

        for (int j = 1; j <= n; j++) if (j != i && f[j][i]) {
            int xs = f[j][i];
            for (int z = n + 1; z <= 2 * n; z++) {
                f[j][z] = (f[j][z] - f[fd][z] * xs) % mo;
            }
        }
        for (int j = n+1; j <= n*2; j++) 
            f[fd][j] = - f[fd][j];
    }
}

ll ans[2000100];
ll sL[N][2],sR[N][2];

int main() {
    freopen("dream.in","r",stdin);
//  freopen("dream.out","w",stdout);
    cin>>n>>m>>q;
    for (ll i = 1; i <= m; i++) {
        ll u,v,w,s,c,p;
        scanf("%lld %lld %lld %lld %lld %lld",
            &e[i].x,&e[i].y,&e[i].Po,&e[i].S,&e[i].C,&e[i].P);
        wsum[e[i].x] = (wsum[e[i].x] + e[i].Po)%mo;
        if (e[i].x==n) i--,m--;
    }

    for (ll i = 1; i <= n; i++) 
        inv[i] = ksm(wsum[i],mo-2);

    for (int i = 1; i <= m; i++) 
        e[i].Po = e[i].Po * inv[e[i].x] % mo;

    sort(e+1,e+1+m);
    for (int i = 1; i <= q; i++) {
        scanf("%d %d",&qu[i].first,&qu[i].second.first);
        qu[i].second.second = i;
    }

    sort(qu+1,qu+1+q);
    gauss();
    int d = 0;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) if (f[e[i].x][j+n]) {
            int xs=f[e[i].x][j+n];
            sR[j][1] = (sR[j][1] - xs * e[i].Po % mo * e[i].S) % mo;
            sR[j][0] = (sR[j][0] + xs * e[i].Po % mo * (e[i].S * e[i].P % mo + e[i].C)) % mo;
        }
    }

    for (int i = 1; i <= q; i++) {
        while (d < m && e[d+1].P <= qu[i].first) {
            d++;
            for (int j = 1; j <= n; j++) if (f[e[d].x][j+n]) {
                int xs=f[e[d].x][j+n];
                sR[j][1] = (sR[j][1] + xs * e[d].Po % mo * e[d].S) % mo;
                sR[j][0] = (sR[j][0] - xs * e[d].Po % mo * (e[d].S * e[d].P % mo + e[d].C)) % mo;

                sL[j][1] = (sL[j][1] + xs * e[d].Po % mo * e[d].S) % mo;
                sL[j][0] = (sL[j][0] + xs * e[d].Po % mo * (e[d].C - e[d].S * e[d].P % mo)) % mo;
            }
        }
        int X = qu[i].second.first;
        ans[qu[i].second.second] = (sL[X][0] + sR[X][0] + qu[i].first * (sL[X][1] + sR[X][1])) % mo;
    }
    for (int i = 1; i <= q; i++) printf("%lld\n",(ans[i]+mo)%mo);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值