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
#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 -鬼畜的优化的更多相关文章
- NOIP模拟题 2017.11.6
题目大意 给定一个大小为n的数组,从中选出一个子集使得这个子集中的数的和能被n整除. 假设开始我没有做出来,那么我就random_shuffle一下,然后计算前缀和,有一个能被n整除,就输出答案.于是 ...
- NOIP模拟题 2017.7.3 - 模拟 - 贪心 - 记忆化搜索
直接暴力模拟,注意判数据结构为空时的取出操作. Code #include<iostream> #include<cstdio> #include<ctime> # ...
- 【NOIP模拟题】行动!行动!(spfa+优化)
spfa不加优化果断tle最后一个点................... 这题和ch的一题很像,只不过这题简单点,这是一个层次图,即有很多个相同的图,这些相同的图之间又存在着练习.. 然后每一次队列 ...
- NOIP模拟题汇总(加厚版)
\(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...
- 8.22 NOIP 模拟题
8.22 NOIP 模拟题 编译命令 g++ -o * *.cpp gcc -o * *.c fpc *.pas 编译器版本 g++/gcc fpc 评测环境 位 Linux, .3GHZ CPU ...
- 【入门OJ】2003: [Noip模拟题]寻找羔羊
这里可以复制样例: 样例输入: agnusbgnus 样例输出: 6 这里是链接:[入门OJ]2003: [Noip模拟题]寻找羔羊 这里是题解: 题目是求子串个数,且要求简单去重. 对于一个例子(a ...
- 9.9 NOIP模拟题
9.9 NOIP模拟题 T1 两个圆的面积求并 /* 计算圆的面积并 多个圆要用辛普森积分解决 这里只有两个,模拟计算就好 两圆相交时,面积并等于中间两个扇形面积减去两个三角形面积 余弦定理求角度,算 ...
- NOIP模拟题17.9.26
B 君的任务(task)[题目描述]与君初相识,犹如故人归.B 君看到了Z 君的第一题,觉得很难.于是自己出了一个简单题.你需要完成n 个任务,第i 任务有2 个属性ai; bi.其中ai 是完成这个 ...
- noip模拟题题解集
最近做模拟题看到一些好的题及题解. 升格思想: 核电站问题 一个核电站有N个放核物质的坑,坑排列在一条直线上.如果连续M个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质. 任务:对于给定 ...
随机推荐
- python tkinter Treeview 事件绑定
def trefun(event): sels= event.widget.selection()#event.widget获取Treeview对象,调用selection获取选择对象名称 for i ...
- 不同版本Hibernate.获取SessionFactory的方式
不同版本Hibernate.获取SessionFactory的方式 Hibernate 版本说明: 我当前使用的是 Hibernate 5.x ,(hibernate-release-5.3.6.Fi ...
- (1)Python3笔记 数据类型之Number与String
一.Number(数值) 1) 整数 : int 2) 浮点数: float type(1) //int type(1.0) // float type(1+1) // int , 2 type(1+ ...
- css3d旋转
一.包裹层添加 -webkit-perspective: 800px; -moz-perspective: 800px; 使子元素获得3D效果支持 二.自持子元素需支持3D效果 -webkit-t ...
- MongoDB Driver:使用正确的姿势连接复制集
from:https://yq.aliyun.com/articles/8461?spm=5176.7937264.222114.10.s2oqcT 摘要: MongoDB复制集(Replica ...
- ling join 报错The specified LINQ expression contains references to queries that are associated with different cont
The specified LINQ expression contains references to queries that are associated with different cont ...
- C#操作XML方法详解
using System.Xml; //初始化一个xml实例 XmlDocument xml=new XmlDocument(); //导入指定xml文件 xml.Load(path); xml. ...
- Vue 的路由实现 Hash模式 和 History模式
Hash 模式: Hash 模式的工作原理是onhashchange事件,Window对象可以监听这个事件... 可以通过改变路径的哈希值,来实现历史记录的保存,发生变化的hash 都会被浏览器给保存 ...
- 在HUE中将文本格式的数据导入hive数仓中
今天有一个需求需要将一份文档形式的hft与fdd的城市关系关系的数据导入到hive数仓中,之前没有在hue中进行这项操作(上家都是通过xshell登录堡垒机直接连服务器进行操作的),特此记录一下. - ...
- scanf,fscanf,sscanf的区别
scanf是从文件中读 sscanf是从字符串中读 scanf是从键盘输入中读 fread :以字节位计算长度,按照指定的长度和次数读取数据,遇到结尾或完成指定长度读取后停止.fscanf :格式 ...