zoukankan      html  css  js  c++  java
  • 大假期集训模拟赛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;
    }
    
  • 相关阅读:
    小程序(二)
    React 之 项目搭建
    mac 终端 常用命令
    css 之 动画(翻转动画例子)
    css 之 单位
    Git 常见操作
    css 之 页面常用布局
    mac版vscode快捷键
    JSX
    Rem适配原理
  • 原文地址:https://www.cnblogs.com/Rubyonly233/p/13437495.html
Copyright © 2011-2022 走看看