大假期集训模拟赛14

置换

题目描述

(negii) 沉迷于研究计算机的构造,他发现简单的二进制竟然能完成如此复杂的计算,当他知道二进制的所有位运算的操作之后,他突发奇想,他想找一种方法能实现二进制位的翻转。具体地,就是我们要将 (7(0111)) 翻转成 (14(1110))(11(1011)) 翻转成 (13(1101))

现在我们给定二进制位数 (k) 以及 (n) 个满足二进制位数不超过 (k) 的数,我们需要输出对应翻转后的数的十进制表示

由于读入量较大,所以 (n) 个数由本机随机生成,具体生成方式如下

int my_rand()
{
    Seed=(214013LL*Seed+2531011)&((1<<k)-1);
    return Seed;
}

我们会给出初始的 (Seed),我们会调用 (n) 次函数,得到需要翻转的 (n) 个数

我们还会采取特殊的输出方式,我们将所有答案 (hash) ,并输出最后的值即可

int ans=0;
void my_hash(int x)
{
    ans=((long long)ans*233+x)%99824353;
}

我们每得到一个数,进行翻转后,我们就会调用一次这个函数,其中传入参数 (x) 为翻转后的数,我们最后输出 (ans) 的值即可

输入格式

(3) 个数,分为 (n)(k)(Seed)

输出格式

一行,一个整数,表示最后 (hash) 值。

样例

样例输入

5 3 233

样例输出

76005766

数据范围与提示

对于前 (50\%) 的数据, (kleq 17)

对于前 (70\%) 的数据, (kleq 20)

对于前 (90\%) 的数据, (kleq 23)

对于 (100\%) 的数据, (nleq 2^k ,kleq 25)

思路

首先先理解一下题意吧,给你三个数,让你用上面的 (rand) 函数来造数据,其实它一点都不 (rand) ,多试几次就会发现,总会是那几个数,顺序都不带变的。

最后输出的时候,将每个翻转后的值 (hash) 一遍,输出 (ans) 即可。

这样我们就主要思考怎么翻转一个二进制的数了。


  • 首先明确一个要点:(k) 表示的是一个数 (x) 转化成二进制的位数。

比如 (k=3) 时,(1) 转化为二进制为 (001) ,翻转后为 (100) ,即 (4)

(k=4) 时,(1) 转化为二进制为 (0001) ,翻转后为 (1000) ,即 (8)

这样我们就更加明确了题意。


怎么实现一个数的翻转呢?

比如我们要翻转 (0001011)

我们将它右移一位,变为 (000101)

如果我们知道了 (000101) 翻转后的数字,将它加上 (2^{k-1}),不就是我们要求的值了吗。

所以我们就可以用前面的将后面的值推出来。

for (int i = 1; i <= EJZ[25]; i++) {
    if (i % 2 == 0) a[i] = a[i >> 1] >> 1;//如果最后一位为0,就不需要加上2^k-1
    else a[i] = (a[i >> 1] >> 1) + EJZ[k - 1];//最后一位为1,需要加上2^k-1
}

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 4e7 + 50, mod = 99824353;
inline int read(){
	int x = 0, w = 1;
	char ch;
	for (; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}

int EJZ[30]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304 ,8388608 , 16777216, 33554432, 67108864};

int n, k, Seed;
int a[maxn];

int my_rand(){
    Seed = (214013LL * Seed + 2531011) & ((1 << k) - 1);
    return Seed;
}

ll ans = 0;

void my_hash(int x){
    ans = (ans * 233 + x) % mod;
}

int main(){
	n = read(), k = read(), Seed = read();
	for (int i = 1; i <= EJZ[25]; i++) {
		if (i % 2 == 0) a[i] = a[i >> 1] >> 1;//如果最后一位为0,就不需要加上2^k-1
		else a[i] = (a[i >> 1] >> 1) + EJZ[k - 1];//最后一位为1,需要加上2^k-1
	}
	for (int i = 1; i <= n; i++) {	
		int x = my_rand();
		my_hash(a[x]);
	}
	printf("%lld
", ans);
	return 0;
}

字符串

题目描述

(negii)(starria) 是好朋友。他们在一起做字符串游戏。

我们定义对于一个字符串的翻转操作:比如翻转的串为 (R),那么他会将前 (|R|−1) 个字符倒序后,插入到该串的最后。举个例子,串 (abd) 进行翻转操作后,将得到 (abdba)

(negii) 进行了若干次(可能为 (0) 次)字符串的翻转操作。

(negii)(starria) 展示出了一个非空串 (S)(S) 是一个串 (R) 的前缀。他想考考 (starria),初始的串 (R) 的长度可能是多少。

(starria) 找到了正在参加模拟赛的你,请你来帮她解决这个问题。但聪明的 (starria) 发现,所有超过 (|S|) 的整数都一定是 (R) 的可能长度,因此你只需要告诉她不超过的 (|S|)(R) 的可能长度即可。

输入格式

输入包含多组数据,第一行一个整数 (T) 表示数据组数。

接下来依次描述每组数据,对于每组数据,一行一个仅由小写字母组成的非空字符串 (S)

输出格式

对于每组数据,输出 (1) 行,从小到大输出 (|R|) 的所有不超过 (|S|) 的可能值,所有值之间用单个空格隔开。

样例

样例输入

3
abcdcb
qwqwq
qaqaqqq

样例输出

4 6
2 3 4 5
6 7

数据范围与提示

对于 (40\%) 的数据,保证 (sum |S|leq 5 imes 10^2)

对于 (60\%) 的数据,保证 (sum |S|leq 5 imes 10^3)

对于 (100\%) 的数据,保证 (|S|leq 10^6,sum |S|leq 5 imes 10^6)

思路

我们会发现:

  • 当我们枚举后 (n/2) 的点时,我们向两边逐渐扩展:

(a[l]=a[r]) ,继续扩展,若 (r=n) 了,则证明这个点符合条件。

(a[l]!=a[r]) ,停止扩展,这个点也不会被记录到答案中。

  • 当我们枚举前 (n/2) 的点时,我们也向两边扩展,不过跟上面不同的是,(l) 会先到达边界 (1)

(a[l]=a[r]) ,继续扩展,若 (l=1) 了,并不能证明这个点是答案,需要判断当前走到的 (r) 点是否符合条件,若 (r) 点符合条件,这个点就是答案。

(a[l]!=a[r]) ,停止扩展,这个点也不会被记录到答案中。


  • 如果我们用 (n^2) 直接去跑,肯定会 (TLE) ,所以我们需要借助一些效率比较高的算法。

法一

可以用一波 (hash),维护一个正向的 (hash) 值,维护一个反向的 (hash) 值,比对正反 (hash) 值即可。

法二

可以用一波 (manacher),记录下以每个节点为中心的回文长度,然后进行比较即可。

代码

法一

#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int maxn = 1e6 + 5;
int T, n;
char a[maxn];
ull h[maxn], f[maxn], p[maxn];
ull H(int l, int r) {
	return h[r] - h[l-1] * p[r-l+1];
}
ull F(int l, int r) {
	return f[l] - f[r+1] * p[r-l+1];
}
int main() {
	p[0] = 1;
	for (int i = 1; i <= 1e6; ++i)
		p[i] = p[i-1] * 131;
	scanf("%d", &T);
	while (T--) {
		scanf("%s", a + 1);
		n = strlen(a + 1);
		f[n+1] = 0;
		for (int i = 1; i <= n; ++i)//正向hash
			h[i] = h[i-1] * 131 + a[i];
		for (int i = n; i >= 1; --i)//反向hash
			f[i] = f[i+1] * 131 + a[i];
		for (int i = 2; i < n; ++i) {
			int l = min(i, n - i + 1);
			if (H(i - l + 1, i) != F(i, i + l - 1)) continue;
			l = i-1 << 1;
			if (l > n || H(1, n - l) == H(1 + l, n)) printf("%d ", i);
		}
		printf("%d
", n);
	}
	return 0;
}

法二

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5e6 + 50, INF = 0x3f3f3f3f, mod = 1e9 + 7;
inline int read(){
	int x = 0, w = 1;
	char ch;
	for (; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}

int T, n, tot, m;
char a[maxn];
char str[maxn];
bool flag[maxn];
int ans[maxn];
bool isblack[maxn];

void Init(){
	str[1] = '$';
	str[2] = '#';
	for (int i = 1; i <= n; i++) {
		str[i * 2 + 1] = a[i];
		str[i * 2 + 2] = '#';
	}
	m = n * 2 + 2;
}

void manacher(){//经典manacher
	int c = 0 ,r = 0;
	for (int i = 1; i <= m; i++) {
		if (r > i) {
			ans[i] = min (ans[2 * c - i], r - i);
		}else {
			ans[i] = 1;
		}
		for (;str[i + ans[i]] == str[i - ans[i]]; ans[i]++);
		if (ans[i] + i > r){
			r = ans[i] + i;
			c = i;
		}
	}
}

int l, r;

bool Judge(int k){
	if(flag[k]) return isblack[k];
	flag[k] = 1;
	r = n - k + 1;
	l = k;
	if (l >= r) {//n/2以后的点
		if (ans[2 * k + 1] / 2 >= r) {
			isblack[k] = 1;
			return 1;
		}else {
			isblack[k] = 0;
			return 0;
		}
	}else {
		if (ans[2 * k + 1] / 2 < l) {//n/2之前的点
			isblack[k] = 0;
			return 0;
		}
		isblack[k] = Judge(k + ans[2 * k + 1] / 2 - 1);
		return isblack[k];
	}
}

int main(){
	T = read();
	while (T--) {
		tot = 0;
		memset(isblack, 0, sizeof isblack);
		memset(ans, 0, sizeof ans);
		memset(flag, 0, sizeof flag);
		scanf("%s", a + 1);
		n = strlen(a + 1);
		if(n==1){
			printf("1
");
			continue;
		}
		Init();
		manacher();
		for (int i = 2; i <= n; i++) {
			if (!flag[i]) Judge(i);
		}
		for (int i = 1; i <= n; i++) {
			if (isblack[i]) {
				printf("%d ",i);
			}
		}	
		printf("
");
	}
	return 0;
}

饼干

题目描述

佩琪最喜欢吃饼干了!但是现在他不准备自己吃,她决定和贝茜分享自己的饼干。佩琪有四种口味的饼干,分别是巧克力味、香草味、红豆味和椰子味。可惜的是,佩琪已经把椰子味的饼干全吃光了,所以现在只剩下前三种了233。。。

巧克力味饼干能带来 (A) 的美味度,香草味饼干能带来 (B) 的美味度,而红豆味饼干可以带来 (A+B) 的美味度。

佩琪会拿出不多于 (N) 块饼干作为送给贝茜的礼物。

为了显得真诚,她想让她拿出的饼干的美味度之和恰好为 (K)

为了显得体面,她决定用一个精美的盒子来装这些饼干。盒子内部有 (N) 个位置,每个位置都可以放一块饼干,或者不放。

现在佩琪想知道有多少种方案可以既显得真诚又显得体面。两种方案不同,当且仅当盒子中某个位置放置的饼干味道不同,或者一个放了饼干而另一个没有。

佩琪自己当然不会做啦,所以她决定请你来帮她解决这个问题。为了防止答案过大,你只需要告诉她答案对 (998244353) 取模的结果就行了。

输入格式

输入只有一行,包含四个整数,分别为(N)(A)(B)(K)

输出格式

输出一行一个整数,即答案对 (998244353) 取模的结果。

样例

样例输入

4 1 2 5

样例输出

40

数据范围与提示

对于前 (30\%) 的数据,(1leq Nleq 10,0leq Kleq 500)

对于前 (50\%) 的数据,(1leq Nleq 1000,0leq Kleq 3000)

对于前 (80\%) 的数据,(1leq Nleq 1e5,0leq Kleq 2e10)

对于 (100\%) 的数据,(1leq Nleq 1e7,0leq Kleq 1e15,0leq A,Bleq 1e5)

思路

  • (30opts) 的分段

显然数据很小,可以直接走 (DFS) ,要么不放,要么放 (A),要么放 (B),要么放 (A+B)


  • (50opts) 的分段

我们可以将 (DFS) 转为 (dp),同样是四种决策,还可以用滚动数组,然而并没有什么卵用。


  • (100opts) 的分段

数论预警!!!

我们可以发现 (A+B) 其实可以拆开,当作选一个 (A),一个 (B)

这样我们可以枚举 (A) 的个数 (i),每次判断 (frac {k} {A} imes i) 是不是 (B) 的倍数,是,(ans+=C_n^i+C_n^{frac {frac{k}{A}*i} {B}})

注意要判断特殊情况:

  • (A=0,B=0,k=0) 时,(ans=4^n)

  • (A eq 0,B eq 0,k=0) 时,(ans=1)

  • (A=0 / B=0,k=0) 时,(ans=2^n)

  • (A=0,B=0,k eq 0) 时,(ans=0)

  • (A=0 / B=0,k!=0) 时,设 (p=frac{k}{max(A,B)})(ans=C_n^p imes 2^p imes 2^{n-p}=C_n^p imes 2^n)

代码

50opts dp

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 1e7 + 50, INF = 0x3f3f3f3f, mod = 998244353;
inline int read(){
	int x = 0, w = 1;
	char ch;
	for (; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}

int n, a, b, c, k;
ll f[2][maxn][4];

ll MOD(ll a, ll b){//快速模
	if(a + b >= mod){
		return a + b - mod;
	}else {
		return a + b;
	}
}

int main(){
	n = read(), a = read(), b = read(), k = read();
	c = a + b;
	f[0][0][0] = 1;
	int s = 0;
	for (register int i = 1; i <= n; i++) {
		s = !s;
		for (register int j = 0; j <= min(i * c, k); j++){
			f[s][j][0] = f[s][j][1] = f[s][j][2] = f[s][j][3] = 0;
		}
		for (register int j = 0; j <= min(i * c, k); j++) {
			f[s][j][0] = (f[s][j][0] + MOD(f[!s][j][0], f[!s][j][1]) + MOD(f[!s][j][2], f[!s][j][3])) % mod;
			if (j >= a) f[s][j][1] = (f[s][j][1] + MOD(f[!s][j-a][0], f[!s][j-a][1]) + MOD(f[!s][j-a][2], f[!s][j-a][3])) % mod;
			if (j >= b) f[s][j][2] = (f[s][j][2] + MOD(f[!s][j-b][0], f[!s][j-b][1]) + MOD(f[!s][j-b][2], f[!s][j-b][3])) % mod;
			if (j >= c) f[s][j][3] = (f[s][j][3] + MOD(f[!s][j-c][0], f[!s][j-c][1]) + MOD(f[!s][j-c][2], f[!s][j-c][3])) % mod;
		}
	}
	printf("%lld
", MOD(MOD(f[s][k][0], f[s][k][1]), MOD(f[s][k][2], f[s][k][3])));
	return 0;
}

正解

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 1e7 + 50, INF = 0x3f3f3f3f, mod = 998244353;
inline int read(){
	int x = 0, w = 1;
	char ch;
	for(; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w; 
}

int n, a, b, k;
int ans;
int jc[maxn + 5], jcny[maxn + 5];

int qpow(int x, int y){//快速幂
	int ans = 1;
	while (y) {
		if (y & 1) ans = ans * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return ans;
}

int Ny(int x){//费马小定理求逆元
	return qpow(x, mod - 2);
}

void Init(){
	jc[0] = 1;
	for (register int i = 1; i <= n; i++) {//求阶乘
		jc[i] = (jc[i-1] * i) % mod;
	}
}

int C(int a, int b){//组合数的计算
	if (a == 0 || a < b) return 0;
	if (b == 0) return 1;
	else return jc[a] * Ny(jc[b]) % mod * Ny(jc[a-b]) % mod;
}

signed main(){
	n = read(), a = read(), b = read(), k = read();
	if (a == 0 && b == 0 && k != 0) {
		printf("0
");
		return 0;
	}
	if (a == 0 && b == 0 && k == 0) {
		ans = 1;
		for (int i = 1; i <= n; i++) {
			ans = (ans * 4) % mod;
		}
		printf("%lld
", ans);
		return 0;
	}else if ((a == 0 || b == 0) && k == 0) {
		ans = 1;
		for (int i = 1; i <= n; i++) {
			ans = (ans * 2) % mod;
		}
		printf("%lld
", ans);
		return 0;
	}
	Init();
	if (a == 0 || b == 0) {
		int p = k / max(a, b);
		ans = C(n, p);
		for (int i = 1; i <= n; i++) {
			ans = (ans * 2) % mod; 
		}
		printf("%lld
", ans % mod);
		return 0;
	}
	for (int i = 0; i <= n && a * i <= k; i++) {
		if ((k - a * i) % b == 0 && (k - a * i) / b <= n) {
			int j = (k - a * i) / b;
			ans = (ans + C(n, i) * C(n, j)) % mod;			
		}
	}	
	printf("%lld
", ans % mod);
	return 0;
}

空间宝石

题目描述

(zP1nG) 很清楚自己打不过灭霸,所以只能在自己出的题里欺负他。

咳咳。这一次他得到了空间宝石 (Tesseract)

世界之树连接着九界,此时灭霸和 (zP1nG) 都在九界的某个地方。而九界是相互无法到达的。(zP1nG) 为了追杀灭霸,决定使用空间宝石的力量到达灭霸身边。因为 (zP1nG) 不擅长使用空间宝石,无法直接开一条从自己的位置到灭霸的位置的传送门,所以他只能无意识地使用空间宝石的力量。(zP1nG) 想知道,在自己胡乱地使用空间宝石后,通过传送门到达灭霸的位置最少需要多长时间。

具体地,九界的编号为 (0sim 8),共有 (n) 道传送门,第 (i) 道传送门为优先级为 (p_i),由 (u_i)(v_i),需要花费 (w_i) 个时间的单向门。传送的规则为:(zP1nG) 按顺序穿过的传送门的优先级必须是单调不降的。例如,(zP1nG) 穿过了三道传送门到达灭霸的位置,这三道传送门的优先级分别为 (1→2→2) 即为一种合法的方式,而优先级分别为 (1→2→1) 是不合法的。

(zP1nG) 会使用 (q) 次宝石的力量来尝试进行传送:其中第 (i) 次尝试会打开数道传送门,这些传送门的优先级会形成 (s_i) 个区间。例如,在某次尝试中 (zP1nG) 打开了三个区间 ([1,2],[4,7],[9,10]),那么优先级在这三个区间内的传送门将全部被打开并允许 (zP1nG) 穿过。你需要告诉 (zP1nG) 在此情况下从自己的位置 (z_i) 到达灭霸所在处 (t_i) 所需的最短时间。尝试结束后所有传送门会关闭。

输入格式

(1) 行包含两个正整数 (n)(S)(S) 的含义见数据范围与约定所述。

(2)(n+1) 行每行包含 (4) 个正整数(p_i,u_i,v_i,w_i)

(n+2) 行包含一个正整数 (q)

(n+3) 至第 (n+q+2) 行每行若干个正整数,其中前三个数为 (z_i,t_i,s_i),之后为 (2 imes s_i) 个正整数,表示每个区间的左右端点。

各变量具体含义见题目描述所述。

输出格式

对于 (zP1nG) 进行的每次尝试,输出一行一个数表示从 (zP1nG) 的位置到灭霸的位置所需的最短时间,如果 (zP1nG) 无法到达灭霸的位置则输出 (-1)

样例

样例输入

6 2
1 2 4 1
2 1 3 3
3 1 2 2
4 3 4 5
5 2 4 3
6 1 4 2
4
1 4 1 1 3
1 4 1 1 4
1 4 2 5 5 2 3
1 4 1 1 6

样例输出

-1
8
5
2

数据范围与提示

对于 (100\%) 的数据,(1≤n≤100,000)(1≤S≤5)(1≤p_i≤2,000)(u_i≠v_i)(z_i≠t_i)(1≤w_i≤100,000,000)(1≤∑s_i≤10,000)

保证每次尝试的区间没有交集,各测试点的约定见下表。

(S) 的含义如下:

(1):保证 (u_i,v_i≤1)

(2):保证每个 (p_i) 各不相同。

(3):保证 (∑s_i≤50)

(4):保证每个询问区间的左端点 (=1)

(5):无特殊限制。

注意:整数 (S) 只是为了让你更容易地完成子任务,你可能不会用到 (S)

思路

很独特的一个思路,我们发现整张图,只有 (9) 个点,这么少的节点,我们可以跑最短路中的 (Floyd),但是优先级怎么处理呢?

我们可以想到矩阵乘法,不过我们这里不是加和,而是取 (min),将同一优先级的最短路存在一个矩阵里。

然后我们可以建一个矩阵的线段树,从小到大存,查询时,注意计算不能够交换,因为矩阵乘不满足乘法交换律。

没啥可讲的,差不多就是线段树板子,将 (int) 换成 (Matrix)

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 2e3 + 50, INF = 0x3f3f3f3f3f3f3f3f;
inline int read(){
	int x = 0, w = 1;
	char ch;
	for(; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w; 
}

int n, S, Q;

struct Node{
	int l, r;
}q[maxn];

bool cmp(Node x, Node y){
	return x.l < y.l;
}

struct Matrix{
	int a[10][10];
	Matrix() {
		memset(a, 0x3f, sizeof a);
		for (int i = 1; i <= 9; i++) {
			a[i][i] = 0;
		}
	}
	Matrix operator * (const Matrix &b) const {
		Matrix c;
		for (int k = 1; k <= 9; k++)
			for (int i = 1; i <= 9; i++)
				for (int j = 1; j <= 9; j++)
					c.a[i][j] = min(c.a[i][j], a[i][k] + b.a[k][j]);
		return c;
	}
}a[maxn],tree[maxn<<2];

void Floyd(){
	for (int s = 1; s <= maxn; s++) {
		for (int k = 1; k <= 9; k++) {
			for (int i = 1; i <= 9; i++) {
				for (int j = 1; j <= 9; j++) {
					a[s].a[i][j] = min (a[s].a[i][j], a[s].a[i][k] + a[s].a[k][j]);
				}
			}
		}
	}
}

void Build(int rt, int l, int r){
	if (l == r) {
		tree[rt] = a[l];
		return;
	}
	int mid = (l + r) >> 1;
	Build(rt << 1, l, mid);
	Build(rt << 1 | 1, mid + 1, r);
	tree[rt] = tree[rt << 1] * tree[rt << 1 | 1];				
}

Matrix Query(int rt, int l, int r, int s, int t){
	if (l == s && r == t) {
		return tree[rt];
	}	
	int mid = (l + r) >> 1;
	if (t <= mid) return Query(rt << 1, l, mid, s, t);
	if (s > mid) return Query(rt << 1 | 1, mid + 1, r, s, t);
	return Query(rt << 1, l, mid, s, mid) * Query(rt << 1 | 1, mid + 1, r, mid + 1 , t);
}

signed main(){
	n = read(), S = read();
	for (int i = 1; i <= n; i++) {
		int p = read(), u = read(), v = read(), w = read();
		a[p].a[u + 1][v + 1] = min(a[p].a[u + 1][v + 1], w);		
	}
	Floyd();
	Build(1, 1, maxn);
	Q = read();
	while (Q--) {
		Matrix ans;
		memset(q, 0, sizeof q);
		int u = read(), v = read(), opt = read();
		u++;
		v++;
		for (int i = 1; i <= opt; i++) {
			q[i].l = read(), q[i].r = read(); 
		}	
		sort(q + 1, q + 1 + opt, cmp);//区间排序
		for (int i = 1; i <= opt; i++) {
			ans = ans * Query(1, 1, maxn, q[i].l, q[i].r);
		}
		if (ans.a[u][v] == INF) {
			printf("-1
");
		}else {
			printf("%lld
", ans.a[u][v]);
		}
	}	
	return 0;
}
原文地址:https://www.cnblogs.com/Rubyonly233/p/13437495.html