1. 程式人生 > >【ACM-ICPC 2018 徐州賽區網絡預賽】E. End Fantasy VIX 血辣 (矩陣運算的推廣)

【ACM-ICPC 2018 徐州賽區網絡預賽】E. End Fantasy VIX 血辣 (矩陣運算的推廣)

有向圖 opened help 問題 with problem rep har ace

Morgana is playing a game called End Fantasy VIX. In this game, characters have nn skills, every skill has its damage. And using skill has special condition. Briefly speaking, if this time you use skill "x", then next time you can use skill "y" (just like combo). There are mm conditions (xi, yiy_i

), and you can‘t break the rules. (that means, if you don‘t have any condition that equals to (xx, yy), then you can‘t use "y" after use "x").

Now, Morgana wants to defeat the boss, he can use skills t times. In the first time he can use any skill, then he should obey the rules. Besides, he has a special armor called "Xue La", he can use this armor and add a debuff to the boss. The debuff will record damage and when it is over, the record damage will be caused again. (that means double damage) The debuff will continue TT

times, and he can use this armor in any time, it won‘t be in conflict with skills.

Finally, Morgana wants to maximize the damage, but it is too difficult. So please help him deal with this problem.

(If Morgana can not use any skill at a time, he will finish the game and the final damage is his total damage at this time.)

Input

First line contains 44 integers n,m,t,T (2≤n≤642 \le n \le 64, 1≤m≤n×(n?1)1 \le m \le n \times (n-1) , 1≤t≤1e9, 1≤T≤t).

In the next mm lines each line contains two integers represent condition (xi,yix_i, y_i) (xi,yi≤nx_i, y_i \le n) .

Then the next line contains nn integers represent the damage of the skills (every skill‘s damage is smaller than 1e81e8).

Output

One line with one integer.

思路

最大傷害可能有兩種情況,即使用血棘()或不使用血辣。使用血辣的情況相當於在一個有向圖上選擇一條經過點數恰好為T的路徑, 將路徑上的點權和翻倍,然後在這條路徑的首尾加上總數不超過(t-T)的點,使得總點權和最大。不使用血辣的情況則比較簡單,直接選擇一條經過點數不超過t的路徑使得點權和最大即可。

聯想到通過鄰接矩陣乘法計算有向圖上從u到v長度為T的路徑條數的思路,不妨嘗試將這裏的問題轉化成可以在矩陣上計算的問題。

用矩陣$A_{ij}$來表示圖上從i到j的某些路徑的點權和的最大值,如果路徑不存在則定義為0。


用“路徑合並”運算(即當一條路徑的終點與另一條路徑的起點均為k時,定義合並的結果為兩條路徑合並後的點權和)和$\max$運算重定義矩陣乘法:$(A \cdot B)_{ij} = \max_{k}\{A_{ik}\ \mathop{Merge}\ B_{kj}\}$.

由於$\max$運算可交換、可結合、存在單位元0(由於題目中點權均為正數),路徑合並運算可結合,且$\max$對“路徑合並”滿足分配律(即$\max(A_{ik}, B_{ik}) \ \mathop{Merge}\ C_{kj} = \max(A_{ik}\ \mathop{Merge}\ C_{kj},B_{ik}\ \mathop{Merge}\ C_{kj})$),可知重定義後的矩陣乘法是可結合的,即可以用快速冪的思路進行分治計算。

考慮上述運算的實際意義,如果我們將題目給出的有向圖寫成具有上述性質的矩陣$G$,則$G^{T-1}_{ij}$即為從i到j恰好經過T-1條邊(即T個點)的所有路徑的最大點權和。這樣我們就知道,想要用血辣的話,只要對$G^{T-1}$中的每個元素翻倍就可以了。

待續

技術分享圖片
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long LL;
  4 const int maxn = 64;
  5 int N, M, t, T, v[maxn];
  6 struct Mat
  7 {
  8     LL A[maxn][maxn];
  9     void Print() const
 10     {
 11         for(int i = 0;i < N;++i)
 12             for(int j = 0;j < N;++j) printf("%lld%c", A[i][j], " \n"[j+1 == N]);
 13         puts("");
 14     }
 15 };
 16 
 17 bool tp;//因為懶得把運算符重載改成函數所以用了一個全局變量,一般認為這樣寫是不嚴謹的
 18         //tp=1時表示路徑長度可以小於t
 19 Mat operator + (const Mat &a, const Mat &b)
 20 {
 21     Mat ans;
 22     for(int i = 0;i < N;++i) for(int j = 0;j < N;++j)
 23         ans.A[i][j] = max(a.A[i][j], b.A[i][j]);
 24     return ans;
 25 }
 26 
 27 Mat operator * (const Mat &a, const Mat &b)
 28 {
 29     Mat ans;
 30     for(int i = 0;i < N;++i) for(int j = 0;j < N;++j)
 31     {
 32         if(tp) ans.A[i][j] = max(a.A[i][j], b.A[i][j]);
 33         else ans.A[i][j] = 0;
 34         for(int k = 0;k < N;++k)
 35         {
 36             if(a.A[i][k] && b.A[k][j])
 37                 ans.A[i][j] = max(ans.A[i][j], a.A[i][k] + b.A[k][j] - v[k]);
 38         }
 39     }
 40     return ans;
 41 }
 42 
 43 Mat G, I;
 44 void init()
 45 {
 46     scanf("%d%d%d%d", &N, &M, &t, &T);
 47     int x, y;
 48     while(M--)
 49     {
 50         scanf("%d%d", &x, &y);
 51         --x, --y;
 52         G.A[x][y] = 1;
 53     }
 54     for(int i = 0;i < N;++i) scanf("%d", &v[i]);
 55     for(int i = 0;i < N;++i) for(int j = 0;j < N;++j)
 56     {
 57         if(G.A[i][j] == 1) G.A[i][j] = v[i] + v[j];
 58     }
 59     for(int i = 0;i < N;++i) for(int j = 0;j < N;++j)
 60         I.A[i][j] = 0;
 61     for(int i = 0;i < N;++i)
 62         I.A[i][i] = v[i];
 63 }
 64 
 65 Mat powmod(Mat a, int n)
 66 {
 67     Mat ans = I;
 68     while(n)
 69     {
 70         if(n & 1) ans = ans * a;
 71         a = a * a;
 72         n >>= 1;
 73     }
 74     return ans;
 75 }
 76 
 77 Mat powmod2(Mat a, Mat g, int n)
 78 {
 79     a = a * g + g * a;
 80     Mat ans = a, pw = I;
 81     while(n)
 82     {
 83         if(n & 1)
 84         {
 85             ans = ans + pw * a + a * pw;
 86             pw = pw * g + g * pw;
 87         }
 88         n >>= 1;
 89         a = a * g + g * a;
 90         g = g * g;
 91     }
 92     return ans;
 93 }
 94 
 95 void work()
 96 {
 97     tp = false;//必須夠T次
 98     Mat a = powmod(G, T-1);
 99     bool useXL = false;
100     for(int i = 0;i < N;++i) for(int j = 0;j < N;++j)
101         if(a.A[i][j])
102         {
103             useXL = true;
104             a.A[i][j] <<= 1;
105         }
106     LL ans = 0;
107     tp = true;//可以不足t次
108     if(useXL)
109     {
110         a = powmod2(a, G, t - T);
111         for(int i = 0;i < N;++i) for(int j = 0;j < N;++j) ans = max(ans, a.A[i][j]);
112     }
113 
114     a = powmod(G, t);
115     for(int i = 0;i < N;++i) for(int j = 0;j < N;++j) ans = max(ans, a.A[i][j]);
116     printf("%lld\n", ans);
117 }
118 
119 int main()
120 {
121     init();
122     work();
123     return 0;
124 }
矩陣運算推廣

【ACM-ICPC 2018 徐州賽區網絡預賽】E. End Fantasy VIX 血辣 (矩陣運算的推廣)