2018.9.9清华集训 T1 dream

4 篇文章 0 订阅
1 篇文章 0 订阅

题意:

数据范围:

Analysis:

首先可以用期望DP推一下,有环,套路的用高斯消元求,但每次询问起点不同,每一次都要高斯消元。考虑转移方程:

fx=y>xPify+cx f x = ∑ y − > x P i ∗ f y + c x

这里的 Pi P i 指走这条边的概率, cx c x 当且仅当 x x 为起点时为1。将 cx c x 移到系数一边,有 n n 个不同的cx。我们可以把它们搞成一个系数矩阵,该矩阵的 bi,i=1 b i , i = 1 ,每一次消元就一起消,这样我们就可以同时搞出以每个点为起点的 fx f x 。考虑答案怎么求?发现如果去掉绝对值可以乘法分配律去掉括号。那么分别就可以离线询问,按 pi p i 排序。实时维护 si s i 的系数即可。复杂度 O(n3+nm+qlogq) O ( n 3 + n m + q log ⁡ q )

Code:

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 4e2 + 5;
const int M = 3e6 + 5;
const int mo = 1e9 + 7;
typedef long long ll;
struct node
{
    int u,v,w,s,c,p;
}e[M],q[M];
int a[N][N],b[N][N],ans[M],su[N],sk[N],sb[N];
int n,m,Q,tot;
inline int read()
{
    int x = 0; char ch = getchar();
    for (; ch < '0' || ch > '9' ; ch = getchar());
    for (; ch >= '0' && ch <= '9' ; ch = getchar()) x = x * 10 + ch - '0';
    return x;
}
inline int pow(int x,int p)
{
    int ret = 1;
    for (; p ; p >>= 1,x = (ll)x * x % mo)
    if (p & 1) ret = (ll)ret * x % mo;
    return ret;
}
bool cmp(node a,node b) { return a.p == b.p ? a.w > b.w : a.p < b.p; }
inline void gossin()
{
    for (int i = 1 ; i <= n ; ++i)
    {
        int ni = pow(a[i][i],mo - 2);
        for (int j = 1 ; j <= n ; ++j)
        if (i != j && a[j][i])
        {
            int x = (ll)a[j][i] * ni % mo;
            for (int k = 1 ; k <= n ; ++k)
            {
                a[j][k] = (a[j][k] - (ll)a[i][k] * x % mo + mo) % mo;
                b[j][k] = (b[j][k] - (ll)b[i][k] * x % mo + mo) % mo;
            }
        }
    }
    for (int i = 1 ; i <= n ; ++i)
    {
        int x = pow(a[i][i],mo - 2);
        for (int j = 1 ; j <= n ; ++j) b[i][j] = (ll)b[i][j] * x % mo;
    }
}
int main()
{
    n = read(),m = read(),Q = read();
    for (int i = 1 ; i <= m ; ++i)
    {
        e[i].u = read(),e[i].v = read(),e[i].w = read();
        e[i].s = read(),e[i].c = read(),e[i].p = read();
        su[e[i].u] = (su[e[i].u] + e[i].w) % mo;
    }
    for (int i = 1 ; i <= n ; ++i) su[i] = pow(su[i],mo - 2),a[i][i] = b[i][i] = 1;
    b[n][n] = 0;
    for (int i = 1 ; i <= m ; ++i)
    if (e[i].u != n) a[e[i].v][e[i].u] = (mo - (ll)su[e[i].u] * e[i].w % mo) % mo;
    gossin();
    for (int i = 1 ; i <= m ; ++i)
    if (e[i].u != n)
    {
        e[i].s = (ll)e[i].s * su[e[i].u] % mo * e[i].w % mo,e[i].c = (ll)e[i].c * su[e[i].u] % mo * e[i].w % mo;
        for (int j = 1 ; j <= n ; ++j)
        {
            sk[j] = (sk[j] + (ll)b[e[i].u][j] * e[i].s % mo * e[i].p % mo + (ll)b[e[i].u][j] * e[i].c % mo) % mo;
            sb[j] = (sb[j] + mo - (ll)b[e[i].u][j] * e[i].s % mo) % mo;
        }
        q[++tot] = e[i];
    }
    for (int i = 1 ; i <= Q ; ++i) q[++tot].p = read(),q[tot].u = read(),q[tot].v = i;
    sort(q + 1,q + tot + 1,cmp);
    for (int i = 1 ; i <= tot ; ++i)
    {
        if (q[i].w)
        {
            for (int j = 1 ; j <= n ; ++j)
            {
                sk[j] = (sk[j] + 2ll * (mo - (ll)b[q[i].u][j] * q[i].s % mo * q[i].p % mo) % mo) % mo;
                sb[j] = (sb[j] + 2ll * (ll)b[q[i].u][j] * q[i].s % mo) % mo;
            }
        } else ans[q[i].v] = (sk[q[i].u] + (ll)q[i].p * sb[q[i].u] % mo) % mo;
    }
    for (int i = 1 ; i <= Q ; ++i) printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值