题解-CF1535

A

最大值小于最小值就不行。

B

先将奇偶分开,偶前奇后。容易发现这样最小。

C

直接模拟,不是 (?) 的放栈里,然后稍微讨论一下即可。

D

写棵线段树模拟然后你就发现不容写线段树。。。

E

贪心从上往下取,然后倍增维护就好。

F

以后注意看到这种数据范围就像根号分治(类比虚树)。先把同一字符集的放在一组,我们发现答案最多为 (2),至少为 (1)。什么时候为 (1)?即两个串切掉 (lcp,lcs) 后有一个串是升序的。

考虑 (n) 很小,直接枚举两个串然后模拟这个过程即可,复杂度 (O(n^2|s|))。如果 (|s|) 很小,枚举每个串的每个子串,考虑有没有一个串是将这部分子串排序后的结果。但是这样会算重,我们只需把排完序后最前或最后不变的区间去掉即可。复杂度玄学 (O(n|s|^2log{s})),所以调一下根号分治的块长就好了。

代码写得非常暴力,好像后一部分复杂度是 (O(n|s|^3log{s}))。但是冲就完事。

#include <bits/stdc++.h>
#define register re
#define pc putchar
#define gc getchar
#define mp make_pair
#define pb push_back
#define pf push_front
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace Standard_IO{
	template <typename T>
	void read(T &x) {
		T flag = 1;
		char ch = gc();
		for (; !isdigit(ch); ch = gc()) if (ch == '-') flag = -1;
		for (x = 0; isdigit(ch); ch = gc()) x = x * 10 + ch - '0';
		x *= flag;
	}
	template <typename T>
	void write(T x) {
		if (x > 9) write(x / 10);
		pc(x % 10 + '0');
	}
	template <typename T>
	void print(T x) {
		if (x < 0) pc('-'), x = -x;
		write(x); pc(' ');
	}
}using namespace Standard_IO;
string s[200005], t;
int n;
int len;
map<string, vector<string>> cla;
unordered_map<string, bool> mark;
int main() {
	read(n);
	for (int i = 1; i <= n; i++) {
		cin >> t;
		s[i] = t;
		sort(t.begin(), t.end());
		cla[t].pb(s[i]);
	}
	len = s[1].length();
	ll ans = 0, before = 0;
	for (auto jzyakioi : cla) {
		vector<string> now = jzyakioi.second;
		n = now.size();
		ans += 1ll * n * before * 1337;
		before += n;
		if (n <= len * 250) {
			for (int i = 0; i < n; i++) {
				for (int j = i + 1; j < n; j++) {
					int lcp = 0, lcs = 0;
					while (now[i][lcp] == now[j][lcp]) lcp++;
					while (now[i][len - lcs - 1] == now[j][len - lcs - 1]) lcs++;
					bool flag1 = 1, flag2 = 1;
					for (int k = lcp + 1; k < len - lcs; k++) {
						if (now[i][k] < now[i][k - 1]) {
							flag1 = 0;
						}
						if (now[j][k] < now[j][k - 1]) {
							flag2 = 0;
						}
					}
					ans += 2;
					if (flag1 || flag2) ans--;
				}
			}
		} else {
			ans += 1ll * n * (n - 1);
			mark.clear();
			for (auto x : now) mark[x] = true;
			for (auto x : now) {
				for (int i = 0; i < len; i++) {
					for (int j = i; j < len; j++) {
						string y = x;
						sort(y.begin() + i, y.begin() + j + 1);
						if (y[i] != x[i] && y[j] != x[j]) {//去重 
							if (mark[y]) {
								ans--;
							}
						}
					}
				}
			}
		}
	}
	print(ans);
	return 0;
}
原文地址:https://www.cnblogs.com/zcr-blog/p/14992857.html