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 }
posted @ 2017-10-28 17:07  阿波罗2003  阅读(257)  评论(0编辑  收藏  举报