noip模拟题 2017.10.28 -kmp -Tarjan -鬼畜的优化
题目大意 给定A串,选择A串的前lB个字符作为B串,再在B串后增加一个字符,问最长的相等的A串前缀和B串的后缀。
Solution 1(KMP)
用1个奇怪的字符连接A串和B串,再用KMP求最长公共前后缀。
Solution 2(Hash)
hash A串的前缀和B的后缀,然后for去比较,取最大的相等的一个
题目大意 找出图上所有点,当它被删掉后使得1和n不连通。
因为这个点删掉后能够使1和n不在同一个联通块内,所以这个点一定是割点。
但是不是所有的割点都合法。当这个点被删掉后,如何判断1和n是否在同一联通块中?
考虑Tarjan,在Tarjan造出的dfs树上,枚举每个割点(除了点1和点n)
假设当前枚举的割点为点i,首先考虑是否点n在点i的子树中,如果不在,说明删掉点i后,1和n一定连通,
现在考虑点n在点i的子树中,但是否存在反祖边使得点n和点1所在联通块连通。
这个根据Tarjan的过程中记录的深度优先值和连向的最早的祖先的值可以很容易得到想到下面一个方法
枚举点i的所有子树,判断点n是否在这中间,如果在,再判断那个点的反祖边有没有连向点i的祖先。
Code
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <algorithm> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cstring> 8 #include <cassert> 9 #include <cmath> 10 #include <cctype> 11 #include <ctime> 12 #include <vector> 13 #include <bitset> 14 #include <stack> 15 #include <queue> 16 #include <map> 17 #include <set> 18 #ifndef WIN32 19 #define Auto "%lld" 20 #else 21 #define Auto "%I64d" 22 #endif 23 using namespace std; 24 typedef bool boolean; 25 typedef pair<int, int> pii; 26 #define smin(_a, _b) _a = min(_a, _b) 27 #define smax(_a, _b) _a = max(_a, _b) 28 #define fi first 29 #define sc second 30 31 template<typename T> 32 inline boolean readInteger(T& u) { 33 static char x = 0; 34 int flag = 1; 35 if(x == -1) 36 return false; 37 while(!isdigit(x = getchar()) && x != '-' && x != -1); 38 if(x == -1) 39 return false; 40 if(x == '-') 41 flag = -1, x = getchar(); 42 for(u = x - '0'; isdigit(x = getchar()); u = u * 10 + x - '0'); 43 u *= flag; 44 return true; 45 } 46 47 const int N = 2e5 + 5; 48 const int M = 4e5 + 5; 49 50 typedef class Edge { 51 public: 52 int end; 53 int next; 54 55 Edge(int end = 0, int next = 0):end(end), next(next) { } 56 }Edge; 57 58 typedef class MapManager { 59 public: 60 int ce; 61 int h[N]; 62 Edge edge[M << 1]; 63 64 MapManager() { } 65 MapManager(int n):ce(0) { 66 memset(h, 0, sizeof(int) * (n + 1)); 67 } 68 69 void addEdge(int u, int v) { 70 edge[++ce] = Edge(v, h[u]); 71 h[u] = ce; 72 } 73 74 void addDoubleEdge(int u, int v) { 75 addEdge(u, v); 76 addEdge(v, u); 77 } 78 79 int start(int node) { 80 return h[node]; 81 } 82 83 Edge& operator [] (int pos) { 84 return edge[pos]; 85 } 86 }MapManager; 87 88 int n, m; 89 MapManager g; 90 91 inline void init() { 92 readInteger(n); 93 readInteger(m); 94 g = MapManager(n); 95 for(int i = 1, u, v; i <= m; i++) { 96 readInteger(u); 97 readInteger(v); 98 g.addDoubleEdge(u, v); 99 } 100 } 101 102 int cnt; 103 int brunch[N]; 104 int dfn[N], ef[N]; 105 boolean exists[N]; 106 void tarjan(int node, int last) { 107 brunch[node] = 0; 108 dfn[node] = ef[node] = ++cnt; 109 for(int i = g.start(node); i; i = g[i].next) { 110 int& e = g[i].end; 111 if(e == last) continue; 112 if(brunch[e] == -1) { 113 tarjan(e, node); 114 brunch[node]++; 115 smin(ef[node], ef[e]); 116 exists[node] = exists[node] || exists[e]; 117 } else { 118 smin(ef[node], dfn[e]); 119 } 120 } 121 // cerr << node << " " << dfn[node] << " " << ef[node] << endl; 122 } 123 124 boolean check(int node) { 125 for(int i = g.start(node); i; i = g[i].next) 126 if(dfn[g[i].end] > dfn[node] && ef[g[i].end] < dfn[node] && exists[g[i].end]) 127 return false; 128 return true; 129 } 130 131 int top; 132 int lis[N]; 133 inline void solve() { 134 cnt = 0; 135 memset(brunch, -1, sizeof(int) * (n + 1)); 136 memset(exists, false, sizeof(int) * (n + 1)); 137 exists[n] = true; 138 tarjan(1, 0); 139 top = 0; 140 for(int i = 2; i < n; i++) 141 if(brunch[i] > 0 && check(i) && exists[i]) 142 lis[top++] = i; 143 printf("%d\n", top); 144 for(int i = 0; i < top; i++) 145 printf("%d ", lis[i]); 146 putchar('\n'); 147 } 148 149 int T; 150 int main() { 151 freopen("home.in", "r", stdin); 152 freopen("home.out", "w", stdout); 153 readInteger(T); 154 while(T--) { 155 init(); 156 solve(); 157 } 158 return 0; 159 }
题目大意 有n个球排成了一个环,球的颜色不是红色就是蓝色,每次操作可以交换相邻的两个球,问最少多少次操作可以使得所有同一种颜色的球都挨在一起。
显然是需要枚举的。
所以考虑枚举中间的位置,然后贪心地把一种颜色往两端塞。
然后会发现有一定单调性,故用两个队列维护一下扔左边的和扔右边的的球。
Code
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <algorithm> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cstring> 8 #include <cassert> 9 #include <cmath> 10 #include <cctype> 11 #include <ctime> 12 #include <vector> 13 #include <bitset> 14 #include <stack> 15 #include <queue> 16 #include <map> 17 #include <set> 18 #ifndef WIN32 19 #define Auto "%lld" 20 #else 21 #define Auto "%I64d" 22 #endif 23 using namespace std; 24 typedef bool boolean; 25 typedef pair<int, int> pii; 26 #define ll long long 27 #define smin(_a, _b) _a = min(_a, _b) 28 #define smax(_a, _b) _a = max(_a, _b) 29 #define fi first 30 #define sc second 31 const signed ll llf = (~0ll) >> 1; 32 template<typename T> 33 inline boolean readInteger(T& u) { 34 static char x = 0; 35 int flag = 1; 36 if(x == -1) 37 return false; 38 while(!isdigit(x = getchar()) && x != '-' && x != -1); 39 if(x == -1) 40 return false; 41 if(x == '-') 42 flag = -1, x = getchar(); 43 for(u = x - '0'; isdigit(x = getchar()); u = u * 10 + x - '0'); 44 u *= flag; 45 return true; 46 } 47 48 const int N = 1e6 + 5; 49 50 int n; 51 deque<int> ql, qr; 52 char s[N]; 53 54 inline void init() { 55 gets(s); 56 n = strlen(s); 57 } 58 59 inline void solve() { 60 ll res = 0, cmp = 0; 61 for(int i = 0; i < n; i++) 62 if(s[i] == 'R') 63 cmp += i - (signed)qr.size(), qr.push_back(i); 64 int p, d1, d2; 65 while(!qr.empty()) { 66 p = qr.back(); 67 d1 = p - (signed)qr.size() + 1; 68 d2 = n - (signed)ql.size() - p - 1; 69 if(d1 > d2) qr.pop_back(), ql.push_front(p), cmp += d2 - d1; 70 else break; 71 } 72 res = cmp; 73 74 for(int i = 1, p, d1, d2; i < n; i++) { 75 boolean flag = false; 76 if(qr.front() < i) { 77 ql.push_back(qr.front()); 78 qr.pop_front(); 79 flag = true; 80 } 81 if(!flag) cmp += (signed)ql.size() - (signed)qr.size(); 82 while(!ql.empty()) { 83 p = ql.front(); 84 d1 = (p - (i + (signed)qr.size()) % n + n) % n; 85 d2 = ((i - (signed)ql.size() + n) % n - p + n) % n; 86 if(d1 < d2) ql.pop_front(), qr.push_back(p), cmp += d1 - d2; 87 else break; 88 } 89 smin(res, cmp); 90 } 91 printf(Auto"\n", res); 92 ql.clear(); 93 qr.clear(); 94 } 95 96 int T; 97 int main() { 98 freopen("sushi.in", "r", stdin); 99 freopen("sushi.out", "w", stdout); 100 readInteger(T); 101 // gets(s); 102 while(T--) { 103 init(); 104 solve(); 105 } 106 return 0; 107 }