最新文章

[SPOJ-GSS4]Can you answer these queries IV 题解

[SPOJ-GSS4]Can you answer these queries IV 题解

题目地址:SPOJ:SPOJ.com – Problem GSS4、洛谷:【S 

[BZOJ3211]花神游历各国 题解

[BZOJ3211]花神游历各国 题解

题目地址:洛谷:【P4145】上帝造题的七分钟2 / 花神游历各国 – 洛谷、 

[BZOJ3038]上帝造题的七分钟2 题解

[BZOJ3038]上帝造题的七分钟2 题解

题目地址:洛谷:【P4145】上帝造题的七分钟2 / 花神游历各国 – 洛谷、BZOJ:Problem 3038. — 上帝造题的七分钟2

题目描述

XLk觉得《上帝造题的七分钟》不太过瘾,于是有了第二部。
“第一分钟,X说,要有数列,于是便给定了一个正整数数列。
第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。
第三分钟,k说,要能查询,于是便有了求一段数的和的操作。
第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围。
第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。
第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
——《上帝造题的七分钟·第二部》
所以这个神圣的任务就交给你了。

题意简述

给你一个序列,两种操作:

  1. 区间每个数开方
  2. 区间求和

输入输出格式

输入格式:
第一行一个整数n,代表数列中数的个数。
第二行n个正整数,表示初始状态下数列中的数。
第三行一个整数m,表示有m次操作。
接下来m行每行三个整数k,l,r,k=0表示给[l,r]中的每个数开平方(下取整),k=1表示询问[l,r]中各个数的和。

输出格式:
对于询问操作,每行输出一个回答。

输入输出样例

输入样例#1:

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

输出样例#1:

19
7
6

说明

1:对于100%的数据,1<=n<=100000,1<=l<=r<=n,数列中的数大于0,且不超过1e12。
2:数据不保证L<=R 若L>R,请自行交换L,R,谢谢!

题解

考虑线段树做,但是发现开放操作没法打标记,因此只能一路递归到底。
然而这样会TLE,因此我们要优化。我们发现每次开方都会对指数数量级减半,没几次开方数就会变为1,1开方仍是1,因此对于那些区间内不含大于1的区间,我们没必要继续递归对它们开方了,节省了不少的时间。

代码

// Code by KSkun, 2018/6
#include <cstdio>
#include <cctype>
#include <cmath>

#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1; register char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = (res << 1) + (res << 3) + c - '0';
    return res * neg;
}

const int MAXN = 100005;

int n, m;

LL a[MAXN], sum[MAXN << 2], mx[MAXN << 2];

#define lch o << 1
#define rch o << 1 | 1
#define mid ((l + r) >> 1)

inline void build(int o, int l, int r) {
    if(l == r) {
        mx[o] = sum[o] = a[l]; return;
    }
    build(lch, l, mid);
    build(rch, mid + 1, r);
    sum[o] = sum[lch] + sum[rch];
    mx[o] = std::max(mx[lch], mx[rch]);
}

inline void modify(int o, int l, int r, int ll, int rr) {
    if(l == r) {
        mx[o] = sum[o] = sqrt(sum[o]); return;
    }
    if(ll <= mid && mx[lch] > 1) modify(lch, l, mid, ll, rr);
    if(rr > mid && mx[rch] > 1) modify(rch, mid + 1, r, ll, rr);
    sum[o] = sum[lch] + sum[rch];
    mx[o] = std::max(mx[lch], mx[rch]);
}

inline LL query(int o, int l, int r, int ll, int rr) {
    if(l >= ll && r <= rr) return sum[o];
    LL res = 0;
    if(ll <= mid) res += query(lch, l, mid, ll, rr);
    if(rr > mid) res += query(rch, mid + 1, r, ll, rr);
    return res;
}

int op, l, r;

int main() {
    n = readint(); 
    for(int i = 1; i <= n; i++) {
        a[i] = readint();
    }
    build(1, 1, n);
    m = readint();
    while(m--) {
        op = readint(); l = readint(); r = readint();
        if(l > r) std::swap(l, r);
        if(op == 0) {
            modify(1, 1, n, l, r);
        } else {
            printf("%lld\n", query(1, 1, n, l, r));
        }
    }
    return 0;
}
[BZOJ3209]花神的数论题 题解

[BZOJ3209]花神的数论题 题解

题目地址:洛谷:【P4317】花神的数论题 – 洛谷、BZOJ:Problem 

[BZOJ2565]最长双回文串 题解

[BZOJ2565]最长双回文串 题解

题目地址:洛谷:【P4555】最长双回文串 – 洛谷、BZOJ:Problem 

Manacher算法原理与实现

Manacher算法原理与实现

概述

Manacher算法是一种用于快速计算字符串中回文串长的算法,复杂度为O(n)。下面介绍该算法的原理及实现细节。

原理

我们从朴素地查找回文串开始,我们枚举回文串的回文中心,并向两边扩展,这种算法是O(n^2)的。我们来想一个问题,如果有串abcbaabcbaabcbaabcba,它本身是回文的,而子串abcba也是回文的,在寻找过程中,abcba可能会被多次遍历到。我们能否把已经找到过的abcba信息利用起来,优化算法呢。Manacher就实现了这种优化。
首先我们要对字符串进行一步处理,因为奇回文abcba和偶回文abba存在不同的模式,需要分别考虑,我们把字符之间都插入一个特殊字符,如#,就可以把偶回文也转化为奇回文的情况了,如abba$#a#b#b#a#。其中,字符串0位置的字符$是用来防止越界的。
这里给一个对齐表方便观察。

示意图

我们考虑在上面的例子中,#a#b#c#b#a#a#b#c#b#a#存在子回文串#a#b#c#b#a#,在下一次遇到该回文串的回文中心时,我们可以考虑在整个大回文串找到这个中心的对称点,就像这样:

#a#b#c#b#a#a#b#c#b#a#
     ^         ^

并把对称点的答案直接拿过来用。如果我们用mx代表当前极大回文串右端点,id代表当前极大回文串中心位置,p数组代表某个位置为中心的最长回文串半径,那么代码写出来应该是这样的:

if(i < mx) p[i] = std::min(p[2 * id - i], mx - i);

然后我们再来扩展修正这个p值,动态地维护当前极大回文串即可。
在处理过的串中p数组代表的半径,而我们发现p数组的值实际上为原串中该位置为中心的最长回文串长+1,因此可以这样直接计算出答案。

实现

本代码可以通过【P3805】【模板】manacher算法 – 洛谷一题。

// Code by KSkun, 2018/6
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>

const int MAXN = 22000005;

char s1[MAXN], s2[MAXN];
int n, tot, p[MAXN], mx;

inline int manacher() {
    s2[tot++] = '$'; s2[tot++] = '#';
    for(int i = 1; i <= n; i++) {
        s2[tot++] = s1[i]; s2[tot++] = '#';
    }
    int mxlen = 0, mx = 0, id;
    for(int i = 1; i < tot; i++) {
        if(i < mx) p[i] = std::min(p[(id << 1) - i], mx - i);
        else p[i] = 1;
        while(s2[i - p[i]] == s2[i + p[i]]) p[i]++;
        if(mx < i + p[i]) {
            id = i; mx = i + p[i];
        }
        mxlen = std::max(mxlen, p[i] - 1);
    }
    return mxlen;
}

int main() {
    scanf("%s", s1 + 1); n = strlen(s1 + 1);
    printf("%d", manacher());
    return 0;
}

参考资料

[BZOJ3438]小M的作物 题解

[BZOJ3438]小M的作物 题解

题目地址:洛谷:【P1361】小M的作物 – 洛谷、BZOJ:Problem  

[HAOI2010]最长公共子序列 题解

[HAOI2010]最长公共子序列 题解

题目地址:洛谷:【P2516】[HAOI2010]最长公共子序列 – 洛谷、B 

[CQOI2014]危桥 题解

[CQOI2014]危桥 题解

题目地址:洛谷:【P3163】[CQOI2014]危桥 – 洛谷、BZOJ:Problem 3504. — [Cqoi2014]危桥

题目描述

Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双向的,但一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。Alice希望在岛屿a1和a2之间往返an次(从al到a2再从a2到al算一次往返)。同时,Bob希望在岛屿b1和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?

题意简述

给你一个图,有的边可以走任意次有的只能走两次。求是否能在a1和a2两个点间往返an次且能在b1和b2两个点间往返bn次。

输入输出格式

输入格式:
本题有多组测试数据。每组数据第一行包含7个空格隔开的整数,分别为N、a1、a2、an、b1、b2、bn。接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的i行j列描述编号i一1和j-l的岛屿间的连接情况,若为”O“则表示有危桥相连:为”N“表示有普通的桥相连:为”X“表示没有桥相连。

输出格式:
对于每组测试数据输出一行,如果他们都能完成愿望输出”Yes“,否则输出”No“。

输入输出样例

输入样例#1:

4 0 1 1 2 3 1
XOXX
OXOX
XOXO
XXOX
4 0 2 1 1 3 2
XNXO
NXOX
XOXO
OXOX

输出样例#1:

Yes
No

说明

4<=N<50
0<=a1, a2, b1, b2<=N-1
1 <=an. b<=50

题解

是不是很像网络流,建图跑就是了。
但是有a1流去b2、b1流去a2的情况,这时只要把a1和b2接到源上,a2和b1接到汇上重新检验就可以了。

代码

// Code by KSkun, 2018/6
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>
#include <queue>

const int MAXN = 55, INF = 1e9;

int n;

struct Edge {
    int to, cap, nxt;
} gra[MAXN * MAXN << 1], grab[MAXN * MAXN << 1];
int head[MAXN], headb[MAXN], tot;

inline void addedge(int u, int v, int cap) {
    gra[tot] = Edge {v, cap, head[u]}; head[u] = tot++;
    gra[tot] = Edge {u, 0, head[v]}; head[v] = tot++;
}

int level[MAXN];

inline bool bfs(int s, int t) {
    std::queue<int> que;
    memset(level, -1, sizeof(level));
    level[s] = 0; que.push(s);
    while(!que.empty()) {
        int u = que.front(); que.pop();
        for(int i = head[u]; ~i; i = gra[i].nxt) {
            int v = gra[i].to;
            if(level[v] == -1 && gra[i].cap) {
                level[v] = level[u] + 1;
                if(v == t) return true;
                que.push(v);
            }
        }
    }
    return level[t] != -1;
}

int cur[MAXN];

inline int dfs(int u, int t, int left) {
    if(u == t || !left) return left;
    int flow = 0;
    for(int &i = cur[u]; ~i; i = gra[i].nxt) {
        int v = gra[i].to;
        if(level[v] == level[u] + 1 && gra[i].cap) {
            int f = dfs(v, t, std::min(left, gra[i].cap));
            if(f) {
                flow += f; left -= f; gra[i].cap -= f; gra[i ^ 1].cap += f;
                if(!left) return flow;
            }
        }
    }
    return flow;
}

inline int dinic(int s, int t) {
    int flow = 0;
    while(bfs(s, t)) {
        memcpy(cur, head, sizeof(head));
        int f;
        while(f = dfs(s, t, INF)) flow += f;
    }
    return flow;
}

int a1, a2, an, b1, b2, bn, S, T;
char tmp[MAXN];

int main() {
    while(scanf("%d", &n) != EOF) {
        memset(head, -1, sizeof(head)); tot = 0;
        S = n + 1; T = S + 1;
        scanf("%d%d%d%d%d%d", &a1, &a2, &an, &b1, &b2, &bn);
        a1++; a2++; b1++; b2++;
        for(int i = 1; i <= n; i++) {
            scanf("%s", tmp + 1);
            for(int j = 1; j <= n; j++) {
                if(tmp[j] == 'O') {
                    addedge(i, j, 2);
                } else if(tmp[j] == 'N') {
                    addedge(i, j, INF);
                }
            }
        }
        memcpy(grab, gra, sizeof(gra));
        memcpy(headb, head, sizeof(head));
        addedge(S, a1, an << 1); addedge(S, b1, bn << 1);
        addedge(a2, T, an << 1); addedge(b2, T, bn << 1);
        if(dinic(S, T) < (an + bn) << 1) {
            puts("No"); continue;
        }
        memcpy(gra, grab, sizeof(gra));
        memcpy(head, headb, sizeof(head));
        addedge(S, a1, an << 1); addedge(S, b2, bn << 1);
        addedge(a2, T, an << 1); addedge(b1, T, bn << 1);
        if(dinic(S, T) < (an + bn) << 1) {
            puts("No"); continue;
        }
        puts("Yes");
    }
    return 0;
}
[CTSC2014]企鹅QQ 题解

[CTSC2014]企鹅QQ 题解

题目地址:洛谷:【P4503】[CTSC2014]企鹅QQ – 洛谷、BZOJ