noip模拟题 2017.10.28 -kmp -Tarjan -鬼畜的优化
2017-10-28 17:07
316 查看
题目大意 给定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
#include <iostream> #include <fstream> #include <sstream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cassert> #include <cmath> #include <cctype> #include <ctime> #include <vector> #include <bitset> #include <stack> #include <queue> #include <map> #include <set> #ifndef WIN32 #define Auto "%lld" #else #define Auto "%I64d" #endif using namespace std; typedef bool boolean; typedef pair<int, int> pii; #define smin(_a, _b) _a = min(_a, _b) #define smax(_a, _b) _a = max(_a, _b) #define fi first #define sc second template<typename T> inline boolean readInteger(T& u) { static char x = 0; int flag = 1; if(x == -1) return false; while(!isdigit(x = getchar()) && x != '-' && x != -1); if(x == -1) return false; if(x == '-') flag = -1, x = getchar(); for(u = x - '0'; isdigit(x = getchar()); u = u * 10 + x - '0'); u *= flag; return true; } const int N = 2e5 + 5; const int M = 4e5 + 5; typedef class Edge { public: int end; int next; Edge(int end = 0, int next = 0):end(end), next(next) { } }Edge; typedef class MapManager { public: int ce; int h ; Edge edge[M << 1]; MapManager() { } MapManager(int n):ce(0) { memset(h, 0, sizeof(int) * (n + 1)); } void addEdge(int u, int v) { edge[++ce] = Edge(v, h[u]); h[u] = ce; } void addDoubleEdge(int u, int v) { addEdge(u, v); addEdge(v, u); } int start(int node) { return h[node]; } Edge& operator [] (int pos) { return edge[pos]; } }MapManager; int n, m; MapManager g; inline void init() { readInteger(n); readInteger(m); g = MapManager(n); for(int i = 1, u, v; i <= m; i++) { readInteger(u); readInteger(v); g.addDoubleEdge(u, v); } } int cnt; int brunch ; int dfn , ef ; boolean exists ; void tarjan(int node, int last) { brunch[node] = 0; dfn[node] = ef[node] = ++cnt; for(int i = g.start(node); i; i = g[i].next) { int& e = g[i].end; if(e == last) continue; if(brunch[e] == -1) { tarjan(e, node); brunch[node]++; smin(ef[node], ef[e]); exists[node] = exists[node] || exists[e]; } else { smin(ef[node], dfn[e]); } } // cerr << node << " " << dfn[node] << " " << ef[node] << endl; } boolean check(int node) { for(int i = g.start(node); i; i = g[i].next) if(dfn[g[i].end] > dfn[node] && ef[g[i].end] < dfn[node] && exists[g[i].end]) return false; return true; } int top; int lis ; inline void solve() { cnt = 0; memset(brunch, -1, sizeof(int) * (n + 1)); memset(exists, false, sizeof(int) * (n + 1)); exists = true; tarjan(1, 0); top = 0; for(int i = 2; i < n; i++) if(brunch[i] > 0 && check(i) && exists[i]) lis[top++] = i; printf("%d\n", top); for(int i = 0; i < top; i++) printf("%d ", lis[i]); putchar('\n'); } int T; int main() { freopen("home.in", "r", stdin); freopen("home.out", "w", stdout); readInteger(T); while(T--) { init(); solve(); } return 0; }
题目大意 有n个球排成了一个环,球的颜色不是红色就是蓝色,每次操作可以交换相邻的两个球,问最少多少次操作可以使得所有同一种颜色的球都挨在一起。
显然是需要枚举的。
所以考虑枚举中间的位置,然后贪心地把一种颜色往两端塞。
然后会发现有一定单调性,故用两个队列维护一下扔左边的和扔右边的的球。
Code
#include <iostream> #include <fstream> #include <sstream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cassert> #include <cmath> #include <cctype> #include <ctime> #include <vector> #include <bitset> #include <stack> #include <queue> #include <map> #include <set> #ifndef WIN32 #define Auto "%lld" #else #define Auto "%I64d" #endif using namespace std; typedef bool boolean; typedef pair<int, int> pii; #define ll long long #define smin(_a, _b) _a = min(_a, _b) #define smax(_a, _b) _a = max(_a, _b) #define fi first #define sc second const signed ll llf = (~0ll) >> 1; template<typename T> inline boolean readInteger(T& u) { static char x = 0; int flag = 1; if(x == -1) return false; while(!isdigit(x = getchar()) && x != '-' && x != -1); if(x == -1) return false; if(x == '-') flag = -1, x = getchar(); for(u = x - '0'; isdigit(x = getchar()); u = u * 10 + x - '0'); u *= flag; return true; } const int N = 1e6 + 5; int n; deque<int> ql, qr; char s ; inline void init() { gets(s); n = strlen(s); } inline void solve() { ll res = 0, cmp = 0; for(int i = 0; i < n; i++) if(s[i] == 'R') cmp += i - (signed)qr.size(), qr.push_back(i); int p, d1, d2; while(!qr.empty()) { p = qr.back(); d1 = p - (signed)qr.size() + 1; d2 = n - (signed)ql.size() - p - 1; if(d1 > d2) qr.pop_back(), ql.push_front(p), cmp += d2 - d1; else break; } res = cmp; for(int i = 1, p, d1, d2; i < n; i++) { boolean flag = false; if(qr.front() < i) { ql.push_back(qr.front()); qr.pop_front(); flag = true; } if(!flag) cmp += (signed)ql.size() - (signed)qr.size(); while(!ql.empty()) { p = ql.front(); d1 = (p - (i + (signed)qr.size()) % n + n) % n; d2 = ((i - (signed)ql.size() + n) % n - p + n) % n; if(d1 < d2) ql.pop_front(), qr.push_back(p), cmp += d1 - d2; else break; } smin(res, cmp); } printf(Auto"\n", res); ql.clear(); qr.clear(); } int T; int main() { freopen("sushi.in", "r", stdin); freopen("sushi.out", "w", stdout); readInteger(T); // gets(s); while(T--) { init(); solve(); } return 0; }
相关文章推荐
- 【NOIP模拟题】Graph(tarjan+dfs)
- 【NOIP 模拟题】[T2]拯救紫萱学姐(kmp+树形dp)
- NOIP 2016 蚯蚓 (luogu 2827 & uoj 264) - 鬼畜的优化
- [noip模拟题]科技节 - 搜索 - 位运算优化
- NOIP模拟题 by天津南开中学 莫凡[tarjan][树剖][并查集]
- 【NOIP模拟题】行动!行动!(spfa+优化)
- NOIP模拟题 2016.7.15 [位运算] [搜索] [递推优化] [计算几何]
- NOIP模拟题 [递推][优化][dp][线段树][离散]
- NOIP模拟题 2016.10.6 [并查集] [联通性] [Tarjan]
- 【NOIP 模拟题】最小生成树(Tarjan求桥)
- HDU 5510 Bazinga(KMP||strstr神器+些许优化)
- [NOIP模拟题][高效算法设计][建模][BFS][记忆化搜索]
- 【字符串处理】【模拟】【120718测试】【NOIP模拟题】NBA工资
- 【NOIP模拟题】连通
- C++——NOIP模拟题——牧场的安排
- noip模拟题11.5
- NOIP模拟题[dfs][DP]
- 【NOIP2017练习】鏖战字符串(斜率优化DP)
- NOIP模拟题 [SPFA][DP][栈结构]
- NOIP模拟题 [线段树][矩阵快速幂]