AHSDFZ 20170305 模拟赛题解 (land genes average)

1.一亩地 land

Description

老 G 是个辛勤的码农,他用了一生的时间,默默种下了一片又一片的代码。现在,他有了一亩代码地。这亩代码可以用一个 n 个节点的树来描述,所有节点可以通过树边互相到达。节点从 0 开始编号。

老 G 渐渐的老去,所以他现在想把他的地传承给他的两个儿子。为了避免儿子产生冲突,他决定将整块地平均分给两个儿子,更具体地,他会将地里 n 个节点平均分给每个儿子。

分割代码地是需要代价的,更具体地,若用树边相连的两个节点最后分给了不同的儿子,则这条边就会产生一定的代价,每条边的代价不一定相等。老 G 想知道最优的分割方案,你能帮助他吗?

Input

第一行一个整数 n,表示树有 n 个节点。保证 n 为偶数。接下来 n-1 行每行三个整数 ui,vi,wi,表示节点 ui,vi 之间有一条边,两个点若分给不同儿子则会产生 wi 的代价。

Output

第一行一个整数,表示分割的最小代价。

第二行 n/2 个用空格分隔的整数,表示分给第一个儿子的所有节点。若有多解任意输出一组即可。

Sample Input

1
2
3
4
5
6
6
0 1 6
0 2 2
1 3 3
1 4 4
2 5 3

Sample Output

1
2
5
0 1 4

Constraints

20%的数据:n <= 20

40%的数据:n <= 60

另有 30%的数据:树为一条链

100%的数据:1 <= n <= 2000 , 0 <= ui,vi < n , 1 <= wi <= 1000

Judge Method

第一行正确得 6 分

第二行方案可行得 4 分

Solution

树形背包。

f[i][j]表示i的子树中选取j个黑点的答案。

转移暴力枚举,因为每对点(i,j)只会在lca有贡献,所以总复杂度O(N^2)

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2002;
const int INF = 1000000007;
int dp[2][maxn][maxn], cnte, h[maxn], n, g[2][maxn];
struct edge_t { int to, next, w; } edge[maxn<<1];
struct hsk { int to, col, next; hsk() {} hsk(int a, int b, int c) { to = a; col = b; next = c; }} to[maxn*maxn*2];
int link[2][maxn][maxn], new_link[2][maxn];
int tot, next[maxn*maxn*2];
void ins(int x, int y, int z) {
    edge[++cnte].to = y;
    edge[cnte].next = h[x];
    edge[cnte].w = z;
    h[x] = cnte;
}
int dfs(int now, int father) {
    int sum = 1, tmp;
    dp[0][now][0] = dp[1][now][1] = 0;
    link[0][now][0] = ++tot;
    next[tot] = 0;
    to[tot] = hsk(now, 0, 0);
    link[1][now][1] = ++tot;
    next[tot] = 0;
    to[tot] = hsk(now, 1, 0);
    for (int i = h[now]; i; i = edge[i].next) {
        if (edge[i].to == father) continue;
        tmp = dfs(edge[i].to, now);
        for (int j = 0; j <= sum + tmp; ++j)
            g[0][j] = g[1][j] = INF;
        for (int j = 0; j <= sum; ++j)
            for (int k = 0; k <= tmp; ++k) {
                int a = dp[1][edge[i].to][k] + dp[0][now][j] + edge[i].w;
                int b = dp[0][edge[i].to][k] + dp[0][now][j];
                int c = dp[0][edge[i].to][k] + dp[1][now][j] + edge[i].w;
                int d = dp[1][edge[i].to][k] + dp[1][now][j];
                if (a < b) {
                    if (g[0][j+k] > a) {
                        new_link[0][j+k] = ++tot;
                        next[tot] = link[0][now][j+k];
                        to[tot] = hsk(edge[i].to, 1, link[1][edge[i].to][k]);
                        g[0][j+k] = a;
                    }
                } else {
                    if (g[0][j+k] > b) {
                        new_link[0][j+k] = ++tot;
                        next[tot] = link[0][now][j];
                        to[tot] = hsk(edge[i].to, 0, link[0][edge[i].to][k]);
                        g[0][j+k] = b;
                    }
                }
                if (c < d) {
                    if(g[1][j+k] > c) {
                        new_link[1][j+k] = ++tot;
                        next[tot] = link[1][now][j];
                        to[tot] = hsk(edge[i].to, 0, link[0][edge[i].to][k]);
                        g[1][j+k] = c;
                    }
                } else {
                    if (g[1][j+k] > d) {
                        new_link[1][j+k] = ++tot;
                        next[tot] = link[1][now][j];
                        to[tot] = hsk(edge[i].to, 1, link[1][edge[i].to][k]);
                        g[1][j+k] = d;
                    }
                }
            }
        sum += tmp;
        for (int j = 0; j <= sum; ++j) {
            dp[0][now][j] = g[0][j];
            dp[1][now][j] = g[1][j];
            link[0][now][j] = new_link[0][j];
            link[1][now][j] = new_link[1][j];
        }
    }
    return sum;
}
int c[maxn];
void dfs2(int now) {
    if (now == 0) return;
    c[to[now].to] = to[now].col;
    dfs2(to[now].next);
    dfs2(next[now]);
}
int main() {
    freopen("land.in", "r", stdin);
    freopen("land.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        for (int j = 0; j <= n; ++j)
            dp[0][i][j] = dp[1][i][j] = INF;
    int u, v, w;
    for (int i = 1; i < n; ++i) {
        scanf("%d %d %d", &u, &v, &w);
        ++u; ++v;
        ins(u, v, w); ins(v, u, w);
    }
    dfs(1, 0);
    if (dp[0][1][n/2] < dp[1][1][n/2]) {
        printf("%d\n", dp[0][1][n/2]);
        dfs2(link[0][1][n/2]);
    } else {
        printf("%d\n", dp[1][1][n/2]);
        dfs2(link[1][1][n/2]);
    }
    for (int i = 1; i <= n; ++i) if (c[i]) printf("%d ", i - 1);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

2.三组基因 genes

Description

小 Y 是个灵魂重组师,他每天要和各种各样的基因玩耍。

这天他正在重组三组基因,三组基因用由小写英文字母组成的字符串 S1,S2,S3 表示。他重组的方式为提取出三个基因中相同的部分,并加以改造。

显然他有非常多种选择方式进行提取,现在他想知道,对于特定的提取长度 l,他有多少种方式进行提取,提取方式不同当且仅当存在某个基因提取的位置不同。

(可以通过样例数据来加深理解。)

Input

共三行,每行一个由小写英文字母组成的字符串。

Output

共 min(|S1|,|S2|,|S3|)行,每行输出一个整数,第 i 行表示提取长度为 i 的提取方法数。

答案模(10^9+7)。

Sample Input

aacbc

baac

aacaa

Sample Output

18

3

1

0

HINT

长度为2时三种提取方法为:

  1. aacbc baac aacaa
  2. aacbc baac aacaa
  3. aacbc baac aacaa

Constraints

20%的数据:1 <= 串长 <= 10

60%的数据:1 <= 串长 <= 1000

100%的数据:1 <= 串长 <= 10^5

Solution

后缀数组+set。

枚举长度L,把height小于L的砍断,那么原后缀数组变成了很多块,对于每块可以求出1、2、3的种数,乘起来就是答案。

另外,本题有后缀自动机的做法:用后缀自动机建立后缀树,每个节点的贡献就是深度*子树内1、2、3点对数。树形DP即可。

Code

后缀数组

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int P = 1000000007;
const int maxn = 600005;
char str[600005], tmp1[600005];
int L1, L2, L3, R1, R2, R3, wa[maxn], wb[maxn], cnt[maxn], n, m, sa[maxn], rank[maxn], height[maxn], h[maxn], cnte;
int tot, lc[maxn<<1], rc[maxn<<1], a[maxn<<1][3], rt;
struct e_d_g_e { int to, next; } edge[maxn];
void ins(int x, int y) { edge[++cnte].to = y; edge[cnte].next = h[x]; h[x] = cnte; }
LL ans, qans[3];
void da() {
    int *x = wa, *y = wb, *z, p, u, v;
    for (int i = 1; i <= m; ++i) cnt[i] = 0;
    for (int i = 1; i <= n; ++i) cnt[x[i] = str[i]]++;
    for (int i = 1; i <= m; ++i) cnt[i] += cnt[i-1];
    for (int i = n; i >= 1; --i) sa[cnt[x[i]]--] = i;
    for (int j = 1; j < n; j <<= 1) {
        p = 0;
        for (int i = n - j + 1; i <= n; ++i) y[++p] = i;
        for (int i = 1; i <= n; ++i) if (sa[i] > j) y[++p] = sa[i] - j;
        for (int i = 1; i <= m; ++i) cnt[i] = 0;
        for (int i = 1; i <= n; ++i) cnt[x[y[i]]]++;
        for (int i = 1; i <= m; ++i) cnt[i] += cnt[i-1];
        for (int i = n; i >= 1; --i) sa[cnt[x[y[i]]]--] = y[i];

        m = 1; y[sa[1]] = 1;
        for (int i = 2; i <= n; ++i) {
            u = sa[i]; v = sa[i-1];
            if (x[u] != x[v] || x[u+j] != x[v+j]) ++m;
            y[u] = m;
        }
        if (m >= n) break;
        z = x; x = y; y = z;
    }
    for (int i = 1; i <= n; ++i) rank[sa[i]] = i;
    p = 0;
    for (int i = 1; i <= n; ++i) {
        if (p > 0) --p;
        if (rank[i] == 1) continue;
        int j = sa[rank[i] - 1];
        while (str[i+p] == str[j+p]) ++p;
        height[rank[i]] = p;
    }
    for (int i = 2; i <= n; ++i) ins(height[i], i);
}
set<int> S;
set<int>::iterator L, R;
void query(int now, int l, int r, int ll, int rr) {
    if (ll <= l && r <= rr) {
        for (int k = 0; k < 3; ++k) qans[k] += a[now][k];
        return;
    } else {
        int mid = (l + r) >> 1;
        if (ll <= mid) query(lc[now], l, mid, ll, rr);
        if (rr > mid) query(rc[now], mid + 1, r, ll, rr);
    }
}
LL query(int l, int r) {
    qans[0] = qans[1] = qans[2] = 0;
    query(rt, 1, n, l, r);
    return qans[0] * qans[1] % P * qans[2] % P;
}
void build(int &now, int l, int r) {
    now = ++tot;
    if (l == r) {
        if (L1 <= sa[l] && sa[l] <= R1) a[now][0] = 1;
        else if (L2 <= sa[l] && sa[l] <= R2) a[now][1] = 1;
        else if (L3 <= sa[l] && sa[l] <= R3) a[now][2] = 1;
    } else {
        int mid = (l + r) >> 1;
        build(lc[now], l, mid);
        build(rc[now], mid+1, r);
        for (int k = 0; k < 3; ++k) a[now][k] = a[lc[now]][k] + a[rc[now]][k];
    }
}
void maghsk(int pos) {
    L = S.upper_bound(pos);
    R = L; --L;
    int l = *L, r = *R;
    ans -= query(l, r - 1);
    S.insert(pos);
    ans += query(l, pos - 1);
    ans += query(pos, r - 1);
    ans = (ans % P + P) % P;
}
int main() {
    freopen("genes.in", "r", stdin);
    freopen("genes.out", "w", stdout);
    scanf("%s", str + 1);
    scanf("%s", tmp1);
    L1 = 1; R1 = strlen(str + 1);
    strcat(str + 1, "#");
    strcat(str + 1, tmp1);
    L2 = R1 + 2; R2 = strlen(str + 1);
    scanf("%s", tmp1);
    strcat(str + 1, "#");
    strcat(str + 1, tmp1);
    L3 = R2 + 2; R3 = strlen(str + 1);
    n = strlen(str + 1);
    m = 1000;
    da();
    build(rt, 1, n);
    int mi = min(min(R1-L1, R2-L2), R3-L3)+1;
    ans = query(1, n);
    S.insert(1); S.insert(n + 1);
    for (int i = 0; i < mi; ++i) {
        for (int j = h[i]; j; j = edge[j].next)
            maghsk(edge[j].to);
        printf("%lld\n", ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

后缀自动机 (by liutao)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include  <stdio.h>
#include   <math.h>
#include   <vector>
#define P 1000000007ll
using namespace std;

const int N=300000;

struct Node
{
    Node *pre,*Son[30];
    vector<Node*>Tson;
    int l,opt,vis;
    long long num[4];
}T[N*2],*root=T,*last=T,*Now=T;

void Extend(int x,int opt)
{
    Node *p=last,*np=++Now;
    np->l=p->l+1;
    for(;p&&!p->Son[x];p=p->pre)
        p->Son[x]=np;
    if(!p)
        np->pre=root;
    else if(p->Son[x]->l==p->l+1)
        np->pre=p->Son[x];
    else
    {
        Node *q=p->Son[x],*nq=++Now;
        *nq=*q;
        nq->num[1]=nq->num[2]=nq->num[3]=0;
        nq->opt=0;
        nq->l=p->l+1;
        q->pre=np->pre=nq;
        for(;p&&p->Son[x]==q;p=p->pre)
            p->Son[x]=nq;
    }
    last=np;
    np->opt=opt;
    np->num[1]=np->num[2]=np->num[3]=0;
}

char s[N];


void Build_Tree(Node* p)
{
    if(p->pre)
        p->pre->Tson.push_back(p);
    p->vis=1;
    for(int i=0;i<=28;i++)
        if(p->Son[i]&&p->Son[i]->vis==0)
            Build_Tree(p->Son[i]);
}

long long Ans[N];


void Work(Node* p)
{
    p->num[p->opt]=1;
    for(int i=0;i<p->Tson.size();i++)
    {
        Node *v=p->Tson[i];
        Work(v);
        p->num[1]+=v->num[1];
        p->num[2]+=v->num[2];
        p->num[3]+=v->num[3];
    }
    if(p==root) return;
    long long now=(p->num[1]*p->num[2]%P)*p->num[3];
    now%=P;
    Ans[p->pre->l+1]+=now;
    Ans[p->pre->l+1]%=P;
    Ans[p->l+1]-=now;
    Ans[p->l+1]%=P;
    Ans[p->l+1]+=P;
    Ans[p->l+1]%=P;
}



int main()
{
    freopen("genes.in","r",stdin);
    freopen("genes.out","w",stdout);
    scanf("%s",s+1);
    int L1=strlen(s+1);
    for(int i=1;i<=L1;i++) Extend(s[i]-'a',1);
    Extend('z'-'a'+1,0);
    scanf("%s",s+1);
    int L2=strlen(s+1);
    for(int i=1;i<=L2;i++) Extend(s[i]-'a',2);
    Extend('z'-'a'+2,0);
    scanf("%s",s+1);
    int L3=strlen(s+1);
    for(int i=1;i<=L3;i++) Extend(s[i]-'a',3);
    Build_Tree(root);
    Work(root);
    int L=min(L1,min(L2,L3));
    long long ans=0;
    for(int i=2;i<=L;i++) Ans[i]+=Ans[i-1],Ans[i]%=P;
    for(int i=1;i<=L;i++) printf("%lld\n",Ans[i]);
    return 0;
}

3.TG主义均贫富 (average)

Description

小 Y 特别喜欢TG主义,这天他正在研究它的优越性。

他发现TG主义为了大众生活经常采取均贫富的方式。

有时候富人非常不听话,会拒绝这个政令,而TG人则会穷追不舍对其强制执行。

更具体地,我们可以把 Z 国看做一个 n 个节点 m 条边的无向图,点从 1 开始编号。

一开始富人在点 S,TG人在 T,每分钟,两队人都会随机采取一次移动,移动的方式也都一样:

位于某个点 i 时,会有 pi 的概率停留点 i,或是有 1-pi 的概率等概率的随机选择 i 的一个邻边移动。

若两队人在某点处相遇,富人就被抓了。

注意,在边上富人是不会被抓住的。

现在TG人想知道它在抓到富人前,他们所走过的路径长度期望和,以便惩治富人。

Input

第一行三个正整数 n,m,t,表示点数边数数据组数。

接下来 m 行,每行两个整数表示一条边。

接下来 n 个实数表示 pi。

接下来 t 行每行前 m 个数 vi 表示边的长度,最后两个数表示 S,T。

Output

共 t 行每行一个实数表示答案。答案保留两位小数。

Sample Input

1
2
3
4
5
6
7
8
4 4 2
1 2
2 3
3 4
1 4
0.5 0.5 0.5 0.5
1 1 1 1 1 2
2 2 2 2 1 3

Sample Output

1
2
4.67
10.67

Constraints

30%的数据:n<=5, t<=10

60%的数据:n<=12, t<=50

100%的数据:1<=n<=22, 1<=t<=500, 1<=vi<=10^6, 0.01<=pi<=0.99

保证图联通,无重边和自环

Solution

高斯消元+逆矩阵+矩阵乘法。

** 注意高斯消元的技巧:用第i行乘上系数去加j而不是用第j行乘系数去加i **

f[i][j]表示A走到i,B走到j的期望长度。

发现f[i][j] = f[j][i]

于是我们可以优化一下常数。。。

然后f[i][i] = 0

剩下的要考虑与i相邻的点u对i的贡献。

如果设p[i]为留在i点的概率,不妨设q[i]为走出i点的概率。

我们要考虑现在在(i,j)下一步走到哪里(加上一个边权后转移到哪里),而不是什么能转移到(i,j)(应该是等价的,但是比较难yy。。考场上不建议这样想)。

f[i][j] = Sum (f[u][j]+w[i][u])*q[i]*p[j] + Sum (f[i][v]+w[j][v])*p[i]*q[j] + Sum (f[u][v]+w[i][u]+w[j][v])*q[i]*q[j] + f[i][j]*p[i]*p[j]

发现这个递推式的状态之间的转移不是拓扑图(会有环)。于是用高斯消元,把w项移到左侧,f[i][j]移到右侧即可。

但是这样会T。

我们发现每次消元系数矩阵不变。于是我们不妨求系数矩阵的逆矩阵,然后每次构造出常数向量,左乘逆矩阵就是答案。

因为构造常数向量是n^2m的,所以总复杂度应该是O(n^6+tn^2*m)的。

其实构造常数矩阵的时候可以达到O(N^2),预处理出来一个奇怪的东西就可以啦。。(反正我也不会但是这样能优化不少复杂度)

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 23*23;
int id[maxn][maxn], eid[maxn][maxn], x[maxn], y[maxn], tot;
double ans[maxn], a[maxn][maxn+maxn], c[maxn][maxn], p[maxn], q[maxn], con[maxn], w[maxn];
void Gauss() {
    double d;
    for (int i = 1; i <= tot; ++i) {
        int ptr;
        for (int j = i; j <= tot; ++j) if (fabs(a[j][i]) > 1e-9) { ptr = j; break; }
        if (ptr != i) for (int j = 1; j <= tot + tot; ++j) swap(a[i][j], a[ptr][j]);
        for (int j = 1; j <= tot; ++j) {
            if (j == i || fabs(a[j][i]) < 1e-9) continue;
            d = a[j][i] / a[i][i];
            for (int k = 1; k <= tot + tot; ++k) a[j][k] = a[j][k] - a[i][k] * d;
            a[j][i] = 0;
        }
    }
    for (int i = 1; i <= tot; ++i) {
        d = a[i][i];
        for (int j = 1; j <= tot + tot; ++j) 
            a[i][j] /= d;
    }
}
int n, m, t;
int main() {
    freopen("average.in", "r", stdin);
    freopen("average.out", "w", stdout);
    scanf("%d %d %d", &n, &m, &t);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        scanf("%d %d", &x, &y);
        eid[x][y] = eid[y][x] = i;
        ++q[x]; ++q[y];
    }
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j < i; ++j) {
            ++tot;
            id[i][j] = id[j][i] = tot;
            x[tot] = i; y[tot] = j;
        }
    for (int i = 1; i <= n; ++i) { scanf("%lf", p + i); q[i] = (-p[i] + 1.0) / q[i]; }
    for (int l = 1; l <= tot; ++l) {
        int i = x[l], j = y[l];
        a[l][l] = p[i] * p[j] - 1.0;
        for (int u = 1; u <= n; ++u) {
            if (eid[u][i]) {
                int t = id[u][j];
                a[l][t] += p[j] * q[i];
                c[l][eid[u][i]] -= p[j] * q[i];
            }
            if (eid[u][j]) {
                int t = id[i][u];
                a[l][t] += p[i] * q[j];
                c[l][eid[u][j]] -= p[i] * q[j];
            }
            for (int v = 1; v <= n; ++v) {
                if (eid[u][i] && eid[v][j]) {
                    int t = id[u][v];
                    a[l][t] += q[i] * q[j];
                    c[l][eid[u][i]] -= q[i] * q[j];
                    c[l][eid[v][j]] -= q[i] * q[j];
                }
            }
        }
    }
    for (int i = 1; i <= tot; ++i) a[i][i+tot] = 1;
    Gauss();
    for (int i = 1; i <= tot; ++i)
        for (int j = 1; j <= tot; ++j)
            a[i][j] = a[i][j+tot];
    while (t--) {
        for (int i = 1; i <= m; ++i) scanf("%lf", w + i);
        int S, T; scanf("%d %d", &S, &T);
        if (S == T) { puts("0.00"); continue; }
        for (int i = 1; i <= tot; ++i) {
            con[i] = 0;
            for (int j = 1; j <= m; ++j)
                con[i] += c[i][j] * w[j];
        }
        S = id[S][T];
        ans[S] = 0;
        for (int j = 1; j <= tot; ++j)
            ans[S] += a[S][j] * con[j];
        printf("%.2lf\n", ans[S]);
    }
}