首页 > 其他分享 >2023/3/17 做题技巧总结

2023/3/17 做题技巧总结

时间:2023-03-17 22:13:28浏览次数:49  
标签:end 技巧 17 int mid rank 2023 return barrel

T1

对于一道题目, 如果描述有类似于“对于 \(\forall x, y \in \mathbb{S}\) 都有 \(x \oplus y \in \mathbb{S}\) (其中 \(\oplus\) 为任意满足交换律的运算)” 的描述时, 我们一定要想到的东西就是线性空间(因为两者的定义是相似的) , 然后我们可以考虑用特别的基来表示这个空间, 比如这道题, 我们就可以用线性基来表示, 然后考虑莫一位为主元的时候构造基里只有一个数这一位是 \(1\) , 根据线性基的性质, 这一定是存在的, 并且是唯一的,然后又因为线性基所有数异或起来是空间最大值, 所以我们就能很容易的数位 DP 了

T2

首先, 一棵树上满足什么条件, 在另一棵树上求值的题方法有很多, 但我觉得对于大部分题来说, 最好的方法还是对于一棵树保留他作为树, 而另一棵将其转化, 变成不是树或者能方便维护的问题。 比如这道题, 考虑第一棵树中取连通块, 这个连通块一定是一棵树, 那么如果有一个点的集合 \(\mathbb{S}\) , 其导出子图满足点数 \(-\) 边数等于 \(1\) , 则这是一个连通块。 所以我们就考虑每条边, 每个点对 T2 所有路径分别去贡献, 首先我们很明显能发现, 某条边 \((u, v)\) 会对一些很有规律的路径做出贡献, 再仔细康康, 我们发现如果处理出 T2 每个点的 dfn, 那么对于 T1 中的边 \((u, v)\) 来说, 在 T2 中找到 \(u\) 和 \(v\) 这两个点, 那么能做贡献的边的两端一定在 \(u\) 或 \(v\) 的子树中(如果 \(u\) 或 \(v\) 在 T2 中一个为另一个的祖先, 那么有一端的点就不是在子树内, 而是在子树外), 两端分别在 \(O(1)\) 段连续的 dfn 序的段上, 那么考虑将 T2 上的一条路径用一个坐标 \((dfn(u), dfn(v))\) 来表示, 那么 T1 中的边 \((u, v)\) 就对 \(O(1)\) 个矩形中的路径有贡献, 而点差不多同理, 对 \(O(deg(u))\) 个矩形中的路径有贡献, 我们只要用一个数据结构, 实现可以 \(+1\) 和 \(-1\) 的区间修改并且查询区间中 \(1\) 的数量, 当然, 矩阵, 无需在线, 都指向了一个方法 树套树 扫描线, 最后部分, 直接上扫描线维护即可

T3

首先, 对于询问和与字符串上 \((l, r)\) 段相关的所有位置有关的问题, 我们一定要想到 SA 和 SAM , 当然, 如果你队 SAM 运用十分熟练, 完全不用考虑 SA 。 这道题两种方法都行, 当然 SAM 的漂亮方法我不会(SAM 我都不会/kk) , 所以我们直接考虑 SA 的方法。 首先我们需要想起一道非常经典的贪心问题, 校门外的树, 有了这个贪心的基础, 我们可以想到, 最多会填的 * 是 \(O(n / (r - l + 1))\) 的, 那么有了这样一个东西, 我们能够想到更号分治, 这里有一个注意点, 我们考虑到了更号分治, 那么我们一定要想清楚小于更号的东西有哪些(一定要想全), 而且千万不要因为一个部分的思路影响了另一个部分的思路。 这道题对询问的区间长短分块, 如果小于更号, 那么预处理的时候用 map 或者 trie 树都可以搞过去。 然后对于大于的, 我们考虑 SA 最基本的性质就是两个位置的公共前缀长度, 等于排完序以后两个位置中间所有位置相邻两个之间公共前缀长度的最小值, 所以我们可以二分出有着 \(S[l...r]\) 这个前缀的位置排完序后是哪一段区间, 设这段区间为 \((h, t)\), 然后对完成 \(SA\) 后的后缀位置, 建立主席树, 这样我们就可以知道 \((h, t)\) 这段区间中有哪些位置了, 然后再进行贪心, 最后因为卡常, 所以块长要调整一下。
AC代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
using namespace std;

#define MAXN 100000
#define MAXM 20
#define INF 0x3f3f3f3f

class suffix_array{
	private:
		template <typename type>
		int* first_sort (type *s, type *end) {
			pair <type, int> *barrel_sort = new pair<type, int>[end - s];
			int *barrel = new int[end - s];
			
			for (type *i = s; i < end; i ++) {
				barrel_sort[i - s] = make_pair (*i, int (i - s));
			}
			sort (barrel_sort, barrel_sort + int(end - s));
			for (pair <type, int> *i = barrel_sort; i < barrel_sort + int(end - s); i ++) {
				barrel[i - barrel_sort] = i->second;
			}
			
			return barrel;
		}
		int query_rank (int *loc, int *end) {
			return loc >= end ? -1 : *loc;
		}
	public:
		template <typename type>
		int* Sort (type *s, type *end) {
			int *barrel = first_sort (s, end);
			int *barrel_end = new int[end - s];
			int *temporary_barrel = new int[end - s];
			int *rank = new int[end - s];
			int num = 1;
			
			*(rank + *barrel) = 0; 
			for (int *i = barrel + 1; i < barrel + int(end - s); i ++) {
				if (*(s + *i) != *(s + *(i - 1))) {
					barrel_end[num - 1] = i - barrel - 1;
					num ++;
				}
				*(rank + *i) = num - 1;
			}
			barrel_end[num - 1] = int(end - s) - 1;
			for (int len = 1; len < end - s; len <<= 1) {
				for (type *i = s; i < end; i ++) {
					temporary_barrel[i - s] = barrel[i - s];
				}
				for (type *i = end - 1; i >= s; i --) {
					if (temporary_barrel[i - s] - len >= 0) {
						barrel[barrel_end[rank[temporary_barrel[i - s] - len]] --] = temporary_barrel[i - s] - len;
					}
				}
				for (int i = 0; i < len; i ++) {
					barrel[barrel_end[rank[i + int(end - s) - len]] --] = i + int(end - s) - len;
				}
				num = 1;
				for (int *i = barrel + 1; i < end - s + barrel; i ++) {
					if (*(rank + *i) != *(rank + *(i - 1)) || query_rank (rank + *i + len, rank + int(end - s)) != query_rank (rank + *(i - 1) + len, rank + int(end - s))) {
						barrel_end[num - 1] = i - barrel - 1;
						num ++;
					}
				}
				barrel_end[num - 1] = int(end - s) - 1;
				for (int t = 0, i = 0; t < num; t ++) {
					while (i <= barrel_end[t]) {
						rank[barrel[i]] = t;
						i ++;
					}
				}
			}
			
			return rank;
		}
}sa;
struct node {
	node *sonl = 0, *sonr = 0;
	int v = 0;
}*rt[MAXN + 5];
struct trie {
	trie *next[26] = {};
	pair<int, int> v;
}*root;

char c[MAXN +5];
int sloc[MAXN + 5];
int st[MAXN + 5][MAXM + 5];
int Log[MAXN + 5];
unsigned long long b[MAXN + 5], Hash[MAXN + 5];
map <unsigned long long, pair<int, int> > Map;

long long find (int l, int r) {
	if (l > r) {
		return 0;
	}
	
	return Hash[r] - Hash[l - 1] * b[r - l + 1];
}
int find_st (int l, int r) {
	if (l > r) {
		return INF;
	}
	else {
		int u = Log[r - l + 1];
		
		return min (st[l][u], st[r - (1 << u) + 1][u]);
	}
}


node* change (node *p, int l, int r, int loc, int v) {
	node *new_p = new node;
	
	if (p) {
		*new_p = *p;
	}
	new_p->v += v;
	if (l == r) {
		return new_p;
	}
	
	int mid = (l + r) >> 1;
	
	if (loc <= mid) {
		new_p->sonl = change (new_p->sonl, l, mid, loc, v); 
	}
	else {
		new_p->sonr = change (new_p->sonr, mid + 1, r, loc, v);
	}
	
	return new_p;
}

int ask (node *p, int l, int r, int h) {
	if (!p || p->v == 0) {
		return -1;
	}
	if (l == r) {
		return l;
	}
	
	int mid = (l + r) >> 1;
	
	if (h > mid) {
		return ask (p->sonr, mid + 1, r, h);
	}
	else {
		int v = ask (p->sonl, l, mid, h);
		
		if (~v) {
			return v;
		}
		else {
			return ask (p->sonr, mid + 1, r, h);
		}
	}
}
int ask (node *p1, node *p2, int l, int r, int h) {
	if (!p2) {
		return ask (p1, l, r, h);
	}
	if (!p1 || p1->v - p2->v == 0) {
		return -1;
	}
	if (l == r) {
		return l;
	}
	
	int mid = (l + r) >> 1;
	
	if (h > mid) {
		return ask (p1->sonr, p2->sonr, mid + 1, r, h);
	}
	else {
		int v = ask (p1->sonl, p2->sonl, l, mid, h);
		
		if (~v) {
			return v;
		}
		else {
			return ask (p1->sonr, p2->sonr, mid + 1, r, h);
		}
	}
}

int main () {
	freopen ("string.in", "r", stdin);
	freopen ("string.out", "w", stdout);
	
	int n, m;
	int Q;
	
	scanf ("%d %d", &n, &m);
	scanf ("%s", c + 1);
	b[0] = 1;
	for (int i = 1; i <= n; i ++) {
		b[i] = b[i - 1] * 13331;
		Hash[i] = Hash[i - 1] * 13331 + c[i];
	}
	Log[0] = 0;
	Log[1] = 0;
	for (int i = 2; i <= n; i ++) {
		Log[i] = Log[i >> 1] + 1;
	} 
	Q = max(1, int(sqrt (n * Log[n])));
	
	int *s = sa.Sort (c + 1, c + 1 + n);
	
	for (int i = 0; i < n; i ++) {
		sloc[s[i]] = i;
	}
	for (int i = 1; i <= n; i ++) {
		rt[i] = change (rt[i - 1], 1, n, sloc[i - 1] + 1, 1);
	}
	for (int i = 1; i < n; i ++) {
		int l = 0, r = min (n - sloc[i - 1], n - sloc[i]);
		
		while (l < r) {
			int mid = (l + r + 1) >> 1;
			
			if (find (sloc[i - 1] + 1, sloc[i - 1] + mid) == find (sloc[i] + 1, sloc[i] + mid)) {
				l = mid;
			}
			else {
				r = mid - 1;
			}
		}
		st[i][0] = l;
	}
	for (int i = 1; i <= Log[n - 1]; i ++) {
		for (int j = 1; j < n - (1 << i) + 1; j ++) {
			st[j][i] = min (st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
		}
	}
	root = new trie;
	for (int i = 1; i <= n; i ++) {
		trie *p = root;
		
		if (!p->next[c[i] - 'a']) {
			p->next[c[i] - 'a'] = new trie;
		}
		p = p->next[c[i] - 'a'];
		for (int j = 2; j <= Q && j <= n - i + 1; j ++) {
			if (!p->next[c[i + j - 1] - 'a']) {
				p->next[c[i + j - 1] - 'a'] = new trie;
			}
			p = p->next[c[i + j - 1] - 'a'];
			if (p->v.second < i) {
				p->v.first ++;
				p->v.second = i + j - 2;
			}
		}
	}
	for (int i = 1; i <= m; i ++) {
		int l, r;
		
		scanf ("%d %d", &l, &r);
		if (l == r) {
			printf ("-1\n");
			
			continue;
		}
		if (r - l + 1 > Q) {
			int hl = 0, hr = s[l - 1];
			int tl = 0, tr = n - s[l - 1] - 1;
			
			while (hl < hr) {
				int mid = (hl + hr + 1) >> 1;
				
				if (find_st (s[l - 1] - mid + 1, s[l - 1]) >= r - l + 1) {
					hl = mid;
				}
				else {
					hr = mid - 1;
				}
			}
			while (tl < tr) {
				int mid = (tl + tr + 1) >> 1;
				
				if (find_st (s[l - 1] + 1, s[l - 1] + mid) >= r - l + 1) {
					tl = mid;
				}
				else {
					tr = mid - 1;
				}
			}
			
			int h = 0;
			int sum = 0;
			
			while (h <= n) {
				h = ask (rt[s[l - 1] + tr + 1], rt[s[l - 1] - hl], 1, n, h);
				if (!(~h)) {
					break;
				}
				h += (r - l);
				sum ++;
			} 
			printf ("%d\n", sum);
		}
		else {
			trie *p = root;
			
			for (int j = l; j <= r; j ++) {
				p = p->next[c[j] - 'a'];
			}
			printf ("%d\n", p->v.first);
		}
	} 
} 

被卡常的做法:

// ubsan: undefined
// accoders
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
using namespace std;

#define MAXN 100000
#define MAXM 20
#define INF 0x3f3f3f3f

class suffix_array {
private:
    template <typename type>
    int *first_sort(type *s, type *end) {
        pair<type, int> *barrel_sort = new pair<type, int>[end - s];
        int *barrel = new int[end - s];

        for (type *i = s; i < end; i++) {
            barrel_sort[i - s] = make_pair(*i, int(i - s));
        }
        sort(barrel_sort, barrel_sort + int(end - s));
        for (pair<type, int> *i = barrel_sort; i < barrel_sort + int(end - s); i++) {
            barrel[i - barrel_sort] = i->second;
        }

        return barrel;
    }
    int query_rank(int *loc, int *end) { return loc >= end ? -1 : *loc; }

public:
    template <typename type>
    int *Sort(type *s, type *end) {
        int *barrel = first_sort(s, end);
        int *barrel_end = new int[end - s];
        int *temporary_barrel = new int[end - s];
        int *rank = new int[end - s];
        int num = 1;

        *(rank + *barrel) = 0;
        for (int *i = barrel + 1; i < barrel + int(end - s); i++) {
            if (*(s + *i) != *(s + *(i - 1))) {
                barrel_end[num - 1] = i - barrel - 1;
                num++;
            }
            *(rank + *i) = num - 1;
        }
        barrel_end[num - 1] = int(end - s) - 1;
        for (int len = 1; len < end - s; len <<= 1) {
            for (type *i = s; i < end; i++) {
                temporary_barrel[i - s] = barrel[i - s];
            }
            for (type *i = end - 1; i >= s; i--) {
                if (temporary_barrel[i - s] - len >= 0) {
                    barrel[barrel_end[rank[temporary_barrel[i - s] - len]]--] = temporary_barrel[i - s] - len;
                }
            }
            for (int i = 0; i < len; i++) {
                barrel[barrel_end[rank[i + int(end - s) - len]]--] = i + int(end - s) - len;
            }
            num = 1;
            for (int *i = barrel + 1; i < end - s + barrel; i++) {
                if (*(rank + *i) != *(rank + *(i - 1)) ||
                    query_rank(rank + *i + len, rank + int(end - s)) !=
                        query_rank(rank + *(i - 1) + len, rank + int(end - s))) {
                    barrel_end[num - 1] = i - barrel - 1;
                    num++;
                }
            }
            barrel_end[num - 1] = int(end - s) - 1;
            for (int t = 0, i = 0; t < num; t++) {
                while (i <= barrel_end[t]) {
                    rank[barrel[i]] = t;
                    i++;
                }
            }
        }

        return rank;
    }
} sa;
struct node {
    node *sonl = 0, *sonr = 0;
    int v = 0;
} * rt[MAXN + 5];

char c[MAXN + 5];
int sloc[MAXN + 5];
int st[MAXN + 5][MAXM + 5];
int Log[MAXN + 5];
unsigned long long b[MAXN + 5], Hash[MAXN + 5];
map<unsigned long long, pair<int, int> > Map;

long long find(int l, int r) {
    if (l > r) {
        return 0;
    }

    return Hash[r] - Hash[l - 1] * b[r - l + 1];
}
int find_st(int l, int r) {
    if (l > r) {
        return INF;
    } else {
        int u = Log[r - l + 1];

        return min(st[l][u], st[r - (1 << u) + 1][u]);
    }
}
node *change(node *p, int l, int r, int loc, int v) {
    node *new_p = new node;

    if (p) {
        *new_p = *p;
    }
    new_p->v += v;
    if (l == r) {
        return new_p;
    }

    int mid = (l + r) >> 1;

    if (loc <= mid) {
        new_p->sonl = change(new_p->sonl, l, mid, loc, v);
    } else {
        new_p->sonr = change(new_p->sonr, mid + 1, r, loc, v);
    }

    return new_p;
}

int ask(node *p, int l, int r, int h) {
    if (!p || p->v == 0) {
        return -1;
    }
    if (l == r) {
        return l;
    }

    int mid = (l + r) >> 1;

    if (h > mid) {
        return ask(p->sonr, mid + 1, r, h);
    } else {
        int v = ask(p->sonl, l, mid, h);

        if (~v) {
            return v;
        } else {
            return ask(p->sonr, mid + 1, r, h);
        }
    }
}
int ask(node *p1, node *p2, int l, int r, int h) {
    if (!p2) {
        return ask(p1, l, r, h);
    }
    if (!p1 || p1->v - p2->v == 0) {
        return -1;
    }
    if (l == r) {
        return l;
    }

    int mid = (l + r) >> 1;

    if (h > mid) {
        return ask(p1->sonr, p2->sonr, mid + 1, r, h);
    } else {
        int v = ask(p1->sonl, p2->sonl, l, mid, h);

        if (~v) {
            return v;
        } else {
            return ask(p1->sonr, p2->sonr, mid + 1, r, h);
        }
    }
}

int main() {
    freopen("string.in", "r", stdin);
    freopen("string.out", "w", stdout);

    int n, m;
    int Q;

    scanf("%d %d", &n, &m);
    Q = sqrt(n);
    scanf("%s", c + 1);
    b[0] = 1;
    for (int i = 1; i <= n; i++) {
        b[i] = b[i - 1] * 13331;
        Hash[i] = Hash[i - 1] * 13331 + c[i];
    }
    Log[0] = 0;
    Log[1] = 0;
    for (int i = 2; i <= n; i++) {
        Log[i] = Log[i >> 1] + 1;
    }

    int *s = sa.Sort(c + 1, c + 1 + n);

    for (int i = 0; i < n; i++) {
        sloc[s[i]] = i;
    }
    for (int i = 1; i <= n; i++) {
        rt[i] = change(rt[i - 1], 1, n, sloc[i - 1] + 1, 1);
    }
    for (int i = 1; i < n; i++) {
        int l = 0, r = min(n - sloc[i - 1], n - sloc[i]);

        while (l < r) {
            int mid = (l + r + 1) >> 1;

            if (find(sloc[i - 1] + 1, sloc[i - 1] + mid) == find(sloc[i] + 1, sloc[i] + mid)) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        st[i][0] = l;
    }
    for (int i = 1; i <= Log[n - 1]; i++) {
        for (int j = 1; j < n - (1 << i) + 1; j++) {
            st[j][i] = min(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 2; j <= Q && j <= n - i + 1; j++) {
            unsigned long long v = find(i, i + j - 1);
            map<unsigned long long, pair<int, int> >::iterator it = Map.find(v);

            if (it == Map.end()) {
                Map.insert(make_pair(v, make_pair(1, i + j - 2)));
            } else if (it->second.second < i) {
                it->second.first++;
                it->second.second = i + j - 2;
            }
        }
    }
    for (int i = 1; i <= m; i++) {
        int l, r;

        scanf("%d %d", &l, &r);
        if (l == r) {
            printf("-1\n");

            continue;
        }
        if (r - l + 1 > Q) {
            int hl = 0, hr = s[l - 1];
            int tl = 0, tr = n - s[l - 1] - 1;

            while (hl < hr) {
                int mid = (hl + hr + 1) >> 1;

                if (find_st(s[l - 1] - mid + 1, s[l - 1]) >= r - l + 1) {
                    hl = mid;
                } else {
                    hr = mid - 1;
                }
            }
            while (tl < tr) {
                int mid = (tl + tr + 1) >> 1;

                if (find_st(s[l - 1] + 1, s[l - 1] + mid) >= r - l + 1) {
                    tl = mid;
                } else {
                    tr = mid - 1;
                }
            }

            int h = 0;
            int sum = 0;

            while (h <= n) {
                h = ask(rt[s[l - 1] + tr + 1], rt[s[l - 1] - hl], 1, n, h);
                if (!(~h)) {
                    break;
                }
                h += (r - l);
                sum++;
            }
            printf("%d\n", sum);
        } else {
            printf("%d\n", Map[find(l, r)].first);
        }
    }
}

标签:end,技巧,17,int,mid,rank,2023,return,barrel
From: https://www.cnblogs.com/flower-dream/p/17228370.html

相关文章

  • 3.17学习总结
    今天将地铁查询系统写完了,所有功能都可实现,我们参考了网上的表结构,将算法优化了一下,所有功能都可使用。     ......
  • 每日总结-23.3.17
    今天写了打卡关于记录和检测连续打卡时长的代码packagecom.example.daka1;importandroidx.appcompat.app.AppCompatActivity;importandroid.content.Intent;impo......
  • 2023年3月17日(软件工程日报)
    访问公共空间1.检查App是否开启了指定权限权限检查需要调用ContextCompat的checkSelfPermission方法,该方法的第一个参数为活动实例,第二个参数为待检查的权限名称,例如存储......
  • 2023/03/15刷题
    B.SorttheArray链接B.SorttheArray这个题原本也是不会然后看了别人的题解,以及学长给了一个思路学长给的思路就是找到最长的可以翻转的区间然后把这个区间翻转过......
  • 2023/03/12刷题
    A.ApplemanandToastman链接A.ApplemanandToastman这个题要计算最大值所以我们肯定直接,每次都减少最少的那个,然后使用一个变量每次把值加上最后打印出来结果就可......
  • 2023/03/13刷题
    C.BoxesPacking链接C.BoxesPacking这个题就是找相同的数字的最大值.因为每一个数字都要放在一个盒子里面打印就可以#include<iostream>#include<algorithm>#i......
  • 2023/03/14刷题
    A.IQtest链接A.IQtest这个题就是给一个数数组,数组有两种情况。要么有n-1个奇数和一个偶数要么有n-1个偶数和一个奇数让我们求出这一个奇数和一个偶数所在数组......
  • 每日总结 3.17
    今天完成了web课程的实验报告一后,继续对查询线路的显示进行了优化处理。页面不会在查询之前显示null,使用foreach进行集合遍历。<%@pagelanguage="java"contentType="......
  • 3.17
    今天我们讨论了该如何快速遍历地铁的所有车站,由于地铁图过于复杂,再加上今天课很多,因此我们目前还没有商量出结果,根据网上内容,我推测出要使用欧拉回路算法,这部分算法对我们......
  • 20230317
    数据结构remake第一天线性表的操作////babyDataStructrue.cpp//dataStructure////Createdbyon2023/3/17.#include<stdio.h>#defineN10#defineMAX20......