比賽-暑假訓練賽1 (26 Jul, 2018)
A. 密碼 沒有想到題解裏機智的 P2-P1 避免重復計算,我以為是一個類似最長公共子串的 DP,OrzOrzOrz。 設輸入分別為 A, B 兩個字符串。f[i][j] 表示 A 串前 i 位與 B 串前 j 位匹配( B 串中字母可以依次在 A 中找到)的方案數。 當 A[i] == B[j], f[i][j] = f[i-1][j-1] 當 A[i] != B[j], f[i][j] = f[i-1][j] 。 顯然 f[i][0] = i 。然後直接這樣寫會爆空間,註意到 i 這維可以滾動掉。答案是 ∑f[i][lenB] 。
B. 獨立集 如果 i < j 且 A[i] < A[j] ,那麽 i, j 就不會連邊,就能夠放在一個集合裏。再推一下會發現第一問是求最長上升子序列。第二問可以腦補出這個東西:某個點確定的充要條件是:原序列以它為最後一個元素和第一個元素的單升,都有且僅有 1 個。後者可以轉換為:反過來的序列裏以它為最後一個元素的單降有且僅有 1 個。把 for 反著寫然後讓A[i] = -A[i],就把反向單降轉化得和正向單升一樣了。
C. 益智遊戲 先跑最短路,然後枚舉邊 x->y = w,對 dis(A, x) + w + dis(y, B) = dis(A, B) 且 dis(C, x) + w + dis(y, D) = dis(C, D) 的邊做一個標記。顯然最終的點都在這些邊上。然後問題轉化為求最長鏈+1(點數)。可以用 DP,f[x] = max{ f[i] } + 1 (滿足有邊從 i 到 x) 。其實寫起來是記憶化搜索。由於上次做過一道什麽轟炸城市的題,也是求最長鏈,被大佬們告知直接 topsort 就可以了不用搜索,所以考試的時候寫了發 topsort 。另外樣例第 2 組就是菊花圖,會卡掉 SPFA (因為邊數有 200000,非常大)。
![技術分享圖片](/img/jia.gif)
1 #include <stdio.h> 2 #include <string.h> 3 4 long long f[250]; 5 char A[320000], B[250]; 6 7 int main() 8 { 9 long long ans = 0; 10 int Alen, Blen, i, j; 11 scanf("%s%s", A+1, B+1); 12 Alen = strlen(A+1), Blen = strlen(B+1); 13 for (i = 1; i <= Alen; ++i) {A14 f[0] = i; 15 for (j = Blen; j >= 1; --j) 16 if (A[i] == B[j]) f[j] = f[j-1]; 17 ans += f[Blen]; 18 } 19 printf("%lld\n", ans); 20 return 0; 21 }
![技術分享圖片](/img/jia.gif)
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 5 using namespace std; 6 7 const int _N = 120000; 8 const int INF = 1e9; 9 10 int A[_N], f[_N], X[_N], Y[_N], cnt[_N]; 11 12 int main() 13 { 14 int i, N, len; 15 scanf("%d", &N); 16 for (i = 1; i <= N; ++i) 17 scanf("%d", &A[i]); 18 f[len = 0] = -INF; 19 for (i = 1; i <= N; ++i) { 20 if (A[i] > f[len]) { f[++len] = A[i], X[i] = len; continue; } 21 int p = lower_bound(f+1, f+1+len, A[i])-f; 22 f[p] = A[i], X[i] = p; 23 } 24 printf("%d\n", len); 25 f[len = 0] = -INF; 26 for (i = N; i >= 1; --i) { 27 if (-A[i] > f[len]) { f[++len] = -A[i], Y[i] = len; continue; } 28 int p = lower_bound(f+1, f+1+len, -A[i])-f; 29 f[p] = -A[i], Y[i] = p; 30 } 31 for (i = 1; i <= N; ++i) 32 if (X[i]+Y[i]-1 == len) ++cnt[X[i]]; 33 for (i = 1; i <= N; ++i) 34 if (X[i]+Y[i]-1 == len && cnt[X[i]] == 1) printf("%d ", i); 35 return 0; 36 }B
![技術分享圖片](/img/jia.gif)
1 #include <stdio.h> 2 #include <algorithm> 3 #include <vector> 4 #include <queue> 5 6 using namespace std; 7 8 typedef long long ll; 9 10 const int _N = 55005; 11 const ll INF = 1e15; 12 13 struct edge { 14 int v; ll w; 15 edge(int v = 0, ll w = 0): 16 v(v), w(w) { } 17 bool operator < (edge const &tmp) const 18 { 19 return w > tmp.w; 20 } 21 }; 22 23 vector<edge> G[3][_N]; 24 priority_queue<edge> Q; 25 queue<edge> Q2; 26 int N, M, beg1, end1, beg2, end2, ind[_N]; 27 ll dis1[_N], dis2[_N], anti1[_N], anti2[_N]; 28 bool mk[_N]; 29 30 void Ins(int id, int x, int y, ll w) { G[id][x].push_back(edge(y, w)); return; } 31 32 void Dijkstra(int id, int beg, ll *dis) 33 { 34 int i; 35 for (i = 1; i <= N; ++i) dis[i] = INF; 36 dis[beg] = 0; 37 while (!Q.empty()) Q.pop(); 38 Q.push(edge(beg, dis[beg])); 39 while (!Q.empty()) { 40 int p = Q.top().v; 41 vector<edge>::iterator it; 42 if (Q.top().w != dis[p]) { Q.pop(); continue; } 43 for (it = G[id][p].begin(); it != G[id][p].end(); ++it) { 44 if (dis[it->v] <= dis[p] + it->w) continue; 45 dis[it->v] = dis[p] + it->w; 46 Q.push(edge(it->v, dis[it->v])); 47 } 48 Q.pop(); 49 } 50 return ; 51 52 } 53 54 int main() 55 { 56 int i, j; 57 scanf("%d%d", &N, &M); 58 for (i = 1; i <= M; ++i) { 59 int x, y; ll w; 60 scanf("%d%d%lld", &x, &y, &w); 61 Ins(0, x, y, w), Ins(1, y, x, w); 62 } 63 scanf("%d%d%d%d", &beg1, &end1, &beg2, &end2); 64 Dijkstra(0, beg1, dis1), Dijkstra(0, beg2, dis2); 65 Dijkstra(1, end1, anti1), Dijkstra(1, end2, anti2); 66 if (dis1[end1] >= INF || dis2[end2] >= INF) { printf("-1\n"); return 0; } 67 for (i = 1; i <= N; ++i) 68 for (j = G[0][i].size()-1; j >= 0; --j) { 69 edge p = G[0][i][j]; 70 if (dis1[i] >= INF || dis2[i] >= INF || anti1[p.v] >= INF || anti2[p.v] >= INF) continue; 71 if (dis1[i]+p.w+anti1[p.v] == dis1[end1] && dis2[i]+p.w+anti2[p.v] == dis2[end2]) 72 Ins(2, i, p.v, p.w), ++ind[p.v]; 73 } 74 for (i = 1; i <= N; ++i) 75 if (!ind[i]) 76 Q2.push(edge(i, 1));//------------------------- 77 ll ans = 0; 78 while (!Q2.empty()) { 79 edge p = Q2.front(); Q2.pop(); 80 ans = max(ans, p.w); 81 for (int i = G[2][p.v].size()-1; i >= 0; --i) { 82 int t = G[2][p.v][i].v; 83 if (!--ind[t]) Q2.push(edge(t, p.w+1)); 84 } 85 } 86 printf("%lld\n", ans); 87 return 0; 88 }C
A密碼 | ||
|
問題描述
假發通過了不懈的努力,得到了將軍家門鎖的密碼(一串小寫英文字母)。但是假發被 十四和猩猩他們盯上了,所以假發需要把密碼傳遞出去。因為假發不想十四他們發現幾松門 前貼的小紙條就是將軍家的密碼,所以他加密了密碼(新八:聽起來有點詭異)。加密方法 如下:隨機地,在密碼中任意位置插入隨機長度的小寫字符串。 不過,假發相信銀桑和他那麽多年小學同學,一定能猜中密碼是什麽的(新八:銀桑什 麽時候成攮夷誌士了!!!)。可是,寫完了小紙條之後,假發覺得有點長,就想截去頭和 尾各一段(可以為空),讓剩下的中間那一段依然包含真~密碼。想著想著,假發就想知道 有多少種可行方案。結果在沈迷於稿紙之際,假發被投進了獄門島(新八:……)。於是, 就由你計算了。
輸入格式
兩行非空字符串,純小寫英文字母,第一行是加密後的密碼,第二行是原密碼。
第一行長度不超過 300000,第二行不超過 200。
輸出格式
一行,有多少種方案。註意:不剪也是一種方案。
樣例輸入 1
abcabcabc
cba
樣例輸出 1
9
樣例輸入 2
abcabcabac
cba
樣例輸出 2
18
提示
【樣例1解釋】 用(L,R)表示一種方案,其中L和R分別表示截去頭和尾的長度。這9鐘方案分別是 (0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)。
B獨立集 | ||
|
問題描述
輸入格式
輸入包含兩行,第一行為 N,
第二行為 1 到 N 的一個全排列
輸出格式
輸出包含兩行,第一行輸出最大獨立集的大小,第二行從小到大輸出一定在最大獨立集 的點的編號。
樣例輸入 1
樣例輸出 1
樣例輸入 2
15
4 14 9 12 11 1 5 6 2 7 13 15 8 10 3
樣例輸出 2
6
7 8 10
樣例輸入 3
3
3 1 2
樣例輸出 3
2
2 3
提示
30%的數據滿足 N<=16
60%的數據滿足 N<=1,000
100%的數據滿足 N<=100,000
C益智遊戲 | ||
|
問題描述
小 P 和小 R 在玩一款益智遊戲。遊戲在一個正權有向圖上進行。 小 P 控制的角色要從 A 點走最短路到 B 點,小 R 控制的角色要從 C 點走最短路到 D 點。 一個玩家每回合可以有兩種選擇,移動到一個相鄰節點或者休息一回合。 假如在某一時刻,小 P 和小 R 在相同的節點上,那麽可以得到一次特殊獎勵,但是在每 個節點上最多只能得到一次。 求最多能獲得多少次特殊獎勵。
輸入格式
第一行兩個整數 n,m 表示有向圖的點數和邊數。 接下來 m 行每行三個整數 xi,yi,li,表示從 xi到 yi有一條長度為 li的邊。 最後一行四個整數 A,B,C,D,描述小 P 的起終點,小 R 的起終點。
輸出格式
輸出一個整數表示最多能獲得多少次特殊獎勵。若小 P 不能到達 B 點或者小 R 不能到達 D 點則輸出-1。
樣例輸入
5 5
1 2 1
2 3 2
3 4 4
5 2 3
5 3 5
1 3 5 4
樣例輸出
2
提示
【數據規模】
對於 30%的數據,滿足 n≤50
對於 60%的數據,滿足 n≤1000,m≤5000 對於
100%的數據,滿足 n≤50000,m≤200000,1≤li≤500000000
比賽-暑假訓練賽1 (26 Jul, 2018)