题目大意 给定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 = ;
int flag = ;
if(x == -)
return false;
while(!isdigit(x = getchar()) && x != '-' && x != -);
if(x == -)
return false;
if(x == '-')
flag = -, x = getchar();
for(u = x - ''; isdigit(x = getchar()); u = u * + x - '');
u *= flag;
return true;
} const int N = 2e5 + ;
const int M = 4e5 + ; typedef class Edge {
public:
int end;
int next; Edge(int end = , int next = ):end(end), next(next) { }
}Edge; typedef class MapManager {
public:
int ce;
int h[N];
Edge edge[M << ]; MapManager() { }
MapManager(int n):ce() {
memset(h, , sizeof(int) * (n + ));
} 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 = , u, v; i <= m; i++) {
readInteger(u);
readInteger(v);
g.addDoubleEdge(u, v);
}
} int cnt;
int brunch[N];
int dfn[N], ef[N];
boolean exists[N];
void tarjan(int node, int last) {
brunch[node] = ;
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] == -) {
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[N];
inline void solve() {
cnt = ;
memset(brunch, -, sizeof(int) * (n + ));
memset(exists, false, sizeof(int) * (n + ));
exists[n] = true;
tarjan(, );
top = ;
for(int i = ; i < n; i++)
if(brunch[i] > && check(i) && exists[i])
lis[top++] = i;
printf("%d\n", top);
for(int i = ; 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 ;
}


  题目大意 有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) >> ;
template<typename T>
inline boolean readInteger(T& u) {
static char x = ;
int flag = ;
if(x == -)
return false;
while(!isdigit(x = getchar()) && x != '-' && x != -);
if(x == -)
return false;
if(x == '-')
flag = -, x = getchar();
for(u = x - ''; isdigit(x = getchar()); u = u * + x - '');
u *= flag;
return true;
} const int N = 1e6 + ; int n;
deque<int> ql, qr;
char s[N]; inline void init() {
gets(s);
n = strlen(s);
} inline void solve() {
ll res = , cmp = ;
for(int i = ; 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() + ;
d2 = n - (signed)ql.size() - p - ;
if(d1 > d2) qr.pop_back(), ql.push_front(p), cmp += d2 - d1;
else break;
}
res = cmp; for(int i = , 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 ;
}

noip模拟题 2017.10.28 -kmp -Tarjan -鬼畜的优化的更多相关文章

  1. NOIP模拟题 2017.11.6

    题目大意 给定一个大小为n的数组,从中选出一个子集使得这个子集中的数的和能被n整除. 假设开始我没有做出来,那么我就random_shuffle一下,然后计算前缀和,有一个能被n整除,就输出答案.于是 ...

  2. NOIP模拟题 2017.7.3 - 模拟 - 贪心 - 记忆化搜索

    直接暴力模拟,注意判数据结构为空时的取出操作. Code #include<iostream> #include<cstdio> #include<ctime> # ...

  3. 【NOIP模拟题】行动!行动!(spfa+优化)

    spfa不加优化果断tle最后一个点................... 这题和ch的一题很像,只不过这题简单点,这是一个层次图,即有很多个相同的图,这些相同的图之间又存在着练习.. 然后每一次队列 ...

  4. NOIP模拟题汇总(加厚版)

    \(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...

  5. 8.22 NOIP 模拟题

      8.22 NOIP 模拟题 编译命令 g++ -o * *.cpp gcc -o * *.c fpc *.pas 编译器版本 g++/gcc fpc 评测环境 位 Linux, .3GHZ CPU ...

  6. 【入门OJ】2003: [Noip模拟题]寻找羔羊

    这里可以复制样例: 样例输入: agnusbgnus 样例输出: 6 这里是链接:[入门OJ]2003: [Noip模拟题]寻找羔羊 这里是题解: 题目是求子串个数,且要求简单去重. 对于一个例子(a ...

  7. 9.9 NOIP模拟题

    9.9 NOIP模拟题 T1 两个圆的面积求并 /* 计算圆的面积并 多个圆要用辛普森积分解决 这里只有两个,模拟计算就好 两圆相交时,面积并等于中间两个扇形面积减去两个三角形面积 余弦定理求角度,算 ...

  8. NOIP模拟题17.9.26

    B 君的任务(task)[题目描述]与君初相识,犹如故人归.B 君看到了Z 君的第一题,觉得很难.于是自己出了一个简单题.你需要完成n 个任务,第i 任务有2 个属性ai; bi.其中ai 是完成这个 ...

  9. noip模拟题题解集

    最近做模拟题看到一些好的题及题解. 升格思想: 核电站问题 一个核电站有N个放核物质的坑,坑排列在一条直线上.如果连续M个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质. 任务:对于给定 ...

随机推荐

  1. Hibernate.基础篇《一》.Hibernate工具类.

    Hibernate.基础篇<一>.Hibernate工具类. 话述: Hibernate.基础篇第一篇,前面是代码.后面再加理论&实践. Hibernate使用的版本是:5.x,在 ...

  2. linux中使用另一用户打开拥有图形界面的程序

    在archlinux中使用oracle用户执行oui无法显示图形界面的问题.结果没解决,后来发现执行 xhost +si:localuser:oracle, 然后再使用oracle用户执行oui即可. ...

  3. [12]Windows内核情景分析 --- MDI

    Mdl意为'内存映射描述符'.'缓冲描述符',一个mdl就代表一个缓冲.(任意一块物理内存,可以同时映射到用户地址空间和系统地址空间的) 设备IO方式分为三种:缓冲方式.直接IO方式.直接方式 缓冲方 ...

  4. 六 js函数和this

    js的所有代码都是由funtion组成,funtion即函数的类型. 一.函数有两种写法 -----1.定义式 function test() { //定义一个函数 console.log(" ...

  5. File §2

    Previously speaking,File can be seen as one ducument, also can be seen as list of documents like dir ...

  6. django中orm使用的注意事项

    必备小知识点 <1> all(): 查询所有结果 <2> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者 ...

  7. python中__call__()方法的用法

    __call__()的用法 __call__()方法能够让类的实例对象,像函数一样被调用: >>> >>> class A(object): def __call_ ...

  8. DataBase(28)

    1.数据库管理系统(DataBase Management System,DBMS):指一种操作和管理数据库的大型软件,用于建立.使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完 ...

  9. redux 数据规律

    counter increase info  todos 为 reducers 文件名 export default combineReducers({ todos, visibilityFilter ...

  10. FTP搭建 共享上网 穿透内网外网

    1.ftp原理介绍 FTP只通过TCP连接,没有用于FTP的UDP组件.FTP不同于其他服务的是它使用了两个端口, 一个数据端口和一个命令端口(或称为控制端口).通常21端口是命令端口,20端口是数据 ...