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个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质. 任务:对于给定 ...
随机推荐
- php 提取多维数组指定列
前言:有时候在开发中会遇到这样的问题,我们需要把有规律的多维数组按照纵向(列)取出,有下面的方法可用: 我们将拿下面的数组来处理: 1 $arr = array( 2 '0' => array( ...
- !! zcl_TD 用法注释02 力攻(动能<4)
力攻(动能<4)创新高下M5可持有力攻(动能<4)不创新高下M5可减仓
- ES6 变量的解构
默认值 let [foo = true] = []; foo // true let [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ...
- redis_bj_01
windows下安装redis 下载地址https://github.com/dmajkic/redis/downloads.下载到的Redis支持32bit和64bit.根据自己实际情况选择,我选择 ...
- oracle 修改表结构,增加列,删除列等
增加一列:ALTER TABLE yourTabbleName ADD columnName dataType; 增加多列:ALTER TABLE yourTabbleName ADD (column ...
- tortoise svn中更改用户
1. Open Windows Explorer.2. Right-click anywhere in the window.3. Click TortoiseSVN → Settings.4. Cl ...
- Unity shader学习之阴影,衰减统一处理
使用unity AutoLight.cginc文件里的内置函数 UNITY_LIGHT_ATTENUATION shader如下: // Upgrade NOTE: replaced 'mul(UNI ...
- wrapper class (Integer 为例)
1,导入 Integer a = 100; Integer b = 100; Integer c = 150; Integer d = 150; a == b; true c == d; false ...
- Gamma函数深入理解
Gamma函数 当n为正整数时,n的阶乘定义如下:n! = n * (n - 1) * (n - 2) * … * 2 * 1. 当n不是整数时,n!为多少?我们先给出答案. 容易证明,Γ(x + 1 ...
- python练习:一行搞定-统计一句话中每个单词出现的个数
一行搞定-统计一句话中每个单词出现的个数 >>> s'i am a boy a bood boy a bad boy' 方式一:>>> dict([(i,s.spl ...