2021牛客寒假算法基础集训营6

回文括号序列计数
链接:https://ac.nowcoder.com/acm/contest/9986/A
来源:牛客网

题目描述
我们定义一个字符串S是回文的,表示S的左右反转和S相同。

我们定义一个字符串是括号序列:

  1. 空串是括号序列。
  2. 两个括号序列P和Q的拼接是括号序列。
  3. 如果P是括号序列,’(’+P+’)'是括号序列。

求长度为 n (0<=n<=10^9) 的回文括号序列的方案数,对 998244353 取膜。
输入描述:
第一行一个 T 表示数据组数。T<=1000000。

接下来 T 行,每行一个 n 。

输出描述:
T 行。对于每组数据,你的答案。
示例1
输入
复制
2
0
1
输出
复制
1
0

脑筋急转弯,既要回文又要是括号串,所以除了空串是1,剩下的都是0

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;

#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define all(x) x.begin(), x.end()
#define fi first
#define se second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

const int N = 2e5 + 10;
const int M = 4e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int _inf = 0xcfcfcfcf;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);

int n, m, k;


int main()
{

	
	int T;
	cin >> T;
	while (T --)
	{
		cin >> n;
		if (n == 0) cout << 1 << endl;
		else cout << 0 << endl;
	}
	
	return 0;
}

系数
链接:https://ac.nowcoder.com/acm/contest/9986/B
来源:牛客网

题目描述
给定一个多项式 f(x)=(x2+x+1)nf(x)=(x
2
+x+1)
n
,求它的第 k 项系数。
输入描述:
第一行,输入 T ,表示数据组数。

接下来 T 行,每行输入 n 和 k 。

输出描述:
对于每组询问,输出系数模 3 后的结果。
示例1
输入
复制
5
2 0
7 4
4 5
5 3
8 15
输出
复制
1
2
1
0
2
备注:
T<=10000

0\le n\le 10^{15},0\le k\le 2n0≤n≤10
15
,0≤k≤2n

因为是对3取余数,所以就是减2和加1没有区别,所以可以那样化简

在这里插入图片描述

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 110;
const int M = 3 * N;
const int mod = 3;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

int qmi(int a, int k)
{
    int res = 1 % mod;
    while (k)
    {
        if (k & 1) res = res % mod * a % mod;
        a = a % mod * a % mod;
        k >>= 1;
    }
    return res % mod;
}


int C(int a, int b)
{
    if (b > a) return 0ll;

    int res = 1;
    for (int i = 1, j = a; i <= b; i ++, j -- )
    {
        res = res % mod * j % mod;
        res = res % mod * qmi(i, mod - 2) % mod;
    }
    return res % mod;
}

int lucas(int a, int b)
{
    if (a < mod && b < mod) return C(a, b) % mod;
    return C(a % mod, b % mod) % mod * lucas(a / mod, b / mod) % mod;
}

signed main(){
	ios;
	int T;
	cin >> T;
	while(T --){
		int n, k;
		cin >> n >> k;
		
		int res;
		if ((2 * n - k) & 1)   res = -1;
		else   res = 1;
		
		cout << ((lucas(n * 2, k) % mod * res) % mod + mod) % mod << endl;  
	}
	
	return 0;
}

末三位
链接:https://ac.nowcoder.com/acm/contest/9986/C
来源:牛客网

题目描述
牛牛最近刚学完指数,他理解了22=4,33=272
2
=4,3
3
=27…

但是,他现在想知道:5^n的末三位是多少?

输入描述:
有多组输入数据。

每组数据输入一个数n,表示指数。

输出描述:
输出5^n的末三位。
示例1
输入
复制
1
3
5
输出
复制
005
125
125
备注:
对于100%的数据,0 <= n <= 1e9。

数据组数 t <= 10^6。

一定会出现循环

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 1e6 + 10;
const int M = 3 * N;
const int mod = 1000;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

int qmi(int a, int b){
	int res = 1;
	while(b){
		if (b & 1)   res = res % mod * a % mod;
		a = a % mod * a % mod;
		b >>= 1;
	}
	return res;
}

signed main(){
	int n;
	while(cin >> n){
		int ans = qmi(5, n);
        printf("%03d\n", ans);
	}

	return 0;
}

划数
链接:https://ac.nowcoder.com/acm/contest/9986/D
来源:牛客网

题目描述
一个智能机器人在黑板上写了n个数,它每次划去任意两个数,并在数列的后面写上这两个数的和对11取模的值。

例:5 6 7 8 9,划去5 6后,数列变为7 8 9 0.

有趣的是,机器人在还剩下两个数的时候突然“罢工”了,已知其中一个数cnt(cnt >= 11),求另外一个数的值。

输入描述:
多组测试数据,以 EOF 结尾。

每组数据,第一行输入n和cnt。

第二行输入n个数,第i个数表示num[i]。

输出描述:
每组数据,输出另外一个数的值。
示例1
输入
复制
6 11
6 7 8 9 10 11
输出
复制
7
备注:
2 <= n <= 150000, 1 <= num[i] <= 1e6.

数据组数 t <= 10,保证数据合法。

要特别的注意的是n为2的情况,这样的话另外的数也有可能是大于等于11的

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 1e6 + 10;
const int M = 3 * N;
const int mod = 998244353;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

int a[N];

signed main(){
	int n, cnt;
	while(scanf("%lld", &n) != EOF){
        cin >> cnt;
			bool flag = false;
	int sum = 0;
	for (int i = 1; i <= n; i ++){
		cin >> a[i];
	//	cout << "--" << endl;
	}
	
	if (n == 2){
		for (int i = 1; i <= 2; i ++){
			if (!flag && a[i] == cnt){
				flag = true;
				continue;
			}
			sum = a[i];
		}
	}
	else{
			for (int i = 1; i <= n; i ++){
		if (!flag && a[i] == cnt){
			flag = true;
			continue;
		}
		sum += a[i];
		sum %= 11ll;	
	}
	}

	
	cout << sum << endl;
	}
	
	return 0;
}

网格
链接:https://ac.nowcoder.com/acm/contest/9986/E
来源:牛客网

题目描述
有一个 n 行 m 列的网格,第 i 行 j 列上有数字 a_{i,j}a
i,j

。每个位置需要从上下左右四个方向中选择互相垂直的两个。

定义 w(x)=x+popcnt(x) ,其中 popcnt(x) 表示 x 的二进制位中 1 的位的数量。

如果两个相邻的位置 (x_1,y_1),(x_2,y_2)(x
1

,y
1

),(x
2

,y
2

) 互相位于对方选择的某个方向上,则对答案由 w(a_{x_1,y_1}\ xor\ a_{x_2,y_2})w(a
x
1

,y
1


xor a
x
2

,y
2


) 的贡献,其中 xor 表示二进制中的按位异或。

小 Z 想问你答案的最大值是多少。
输入描述:
第一行,输入 n,m 。

接下来 n 行 m 列,输入这个网格。
输出描述:
输出答案的最大值。
示例1
输入
复制
3 3
1 3 6
3 2 4
7 4 0
输出
复制
38
备注:
对于 100% 的数据,1\le n,m\le 1000,0\le a_{i,j}<10241≤n,m≤1000,0≤a
i,j

<1024 。

每个位置可以选择两个相互垂直的,也就是说每个位置就是左右两边选一个,上下两个位置,所以这样的话,就是左右和上下是单独分开的,所以先枚举每一行,看当前这一行的每个位置选的左边还是右边,如果状态是0的话表示当前的这个选的是左边,如果状态是1的话就表示当前的这个选的是右边,然后每个状态都可以从前面的两个状态转移,然后再枚举列即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 1200 + 10;
const int M = N * N;
const int mod = 998244353;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

int n, m;
int f[N][N][3];
int a[N][N];

int calc(int x){
	int ans = x;
	while(x){
		if (x & 1)   ans ++;
		x >>= 1;
	}
	return ans;
}

signed main(){
 	ios;
 	cin >> n >> m;
 	for (int i = 1; i <= n; i ++){
 		for (int j = 1; j <= m; j ++){
 			cin >> a[i][j];
		 }
	 }
	 
	int ans = 0;
	for (int i = 1; i <= n; i ++){
		for (int j = 2; j <= m; j ++){
			f[i][j][0] = max(f[i][j][0], f[i][j - 1][1] + calc(a[i][j] ^ a[i][j - 1]));
			f[i][j][1] = max(f[i][j - 1][0], f[i][j - 1][1]); 
		}
		
		ans += max(f[i][m][0], f[i][m][1]);
	} 
	
	memset(f, 0, sizeof f);
	
	for (int i = 1; i <= m; i ++){
		for (int j = 2; j <= n; j ++){
			f[j][i][0] = max(f[j][i][0], f[j - 1][i][1] + calc(a[j][i] ^ a[j - 1][i]));
			f[j][i][1] = max(f[j - 1][i][0], f[j - 1][i][1]);
		}
		
		ans += max(f[n][i][0], f[n][i][1]);
	}
	
	cout << ans << endl;
	
	return 0;
}

组合数问题
链接:https://ac.nowcoder.com/acm/contest/9986/F
来源:牛客网

题目描述
小 M 很喜欢组合数。

小 Z 给了她一个数 n (n为偶数),让她计算 \binom{n}{0}+\binom{n}{2}+\binom{n}{4}…+\binom{n}{n}(
0
n

)+(
2
n

)+(
4
n

)…+(
n
n

) ,小 M 一下子就秒掉了,觉得题好简单。

因此,小 Z 给了她一个难题:给定一个数 n (n 是4的倍数),计算 \binom{n}{0}+\binom{n}{4}+\binom{n}{8}+…+\binom{n}{n}(
0
n

)+(
4
n

)+(
8
n

)+…+(
n
n

) ,答案对 998244353 取模。

小 M 不会做,请你来帮帮她吧!
输入描述:
输入一个数 n 。
输出描述:
输出答案对 998244353 取模的值。
示例1
输入
复制
12
输出
复制
992
备注:
对于所有的数据,1\le n\le 10^{18}1≤n≤10
18

首先要知道简单的怎么算,然后类比求出复杂的,求简单的话我们首先用二次项定理化简,然后把奇数项消去,这样的话我们可以拼凑出来,然后求复杂的话我们还需要把2的奇数倍消去,把奇数项消去利用的是-1的奇数次是-1,消除那个我们可以利用i的2次方是-1,就可以消去

在这里插入图片描述

机器人
链接:https://ac.nowcoder.com/acm/contest/9986/G
来源:牛客网

题目描述
有 n 个机器人,每个机器人会读入一个 x ,并返回 ax+b 。

现在银临姐姐手里有一个数 x ,她想将机器人按某种顺序排列,使得最终返回得到的 x 尽可能大。

但是计算量太大啦,请你编个程序帮帮她吧。
输入描述:
第一行读入 n,x ,接下来 n 行依次输入 a_i, b_ia
i

,b
i


输出描述:
输出最大值。
示例1
输入
复制
2 2
11 4
5 14
输出
复制
268
备注:
对于所有的数据,1\le n,x,a_i,b_i\le 201≤n,x,a
i

,b
i

≤20 。

数据范围这么小,可以考率状态压缩DP,所有的状态满的时候就是所有组的a和b都用到了,一开始是0,都没用到,然后dfs动态规划即可。第二个方法是贪心,假如现在只有两个,分别表示出a先用和b先用的值,然后求这个不等式,如果可以消去x,就能把这个贪心出来

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(INT x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 50;
const int M = 3 * N;
const int mod = 3;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

int a[N], b[N];
__int128 f[(1 << 20) + 100]; 
int n, x;

INT dfs(int val){
	if (f[val] != 0)   return f[val];
	
	for (int i = 0; i < n; i ++){
		if ((val >> i) & 1){
			int t = val ^ (1 << i);
			f[val] = max(f[val], (INT)(dfs(t) * a[i + 1] + b[i + 1]));
		}
	}
	return f[val];
}

signed main(){
	ios;
	cin >> n >> x;
	for (int i = 1; i <= n; i ++){
		cin >> a[i] >> b[i];
	}
	
	f[0] = x;
	
	print(dfs((1 << n) - 1));
	
	return 0;
}

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(INT x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 110;
const int M = 3 * N;
const int mod = 998244353;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

INT a[N], b[N], temp[N];
INT n, x;

struct Node{
	INT a, b;
	bool operator<(const Node &W)const{
		return  (W.a- 1) * b > (a - 1) * W.b;
	}
}node[N];

signed main(){
	gt(n), gt(x);
	
	for (int i = 1; i <= n; i ++){
		gt(node[i].a);
		gt(node[i].b);
	}
	
	sort(node + 1, node + 1 + n);
	
	INT ans = x;
	
	for (int i = 1; i <= n; i ++){
		ans *= (node[i].a);
	}
	
	temp[n + 1] = 1;
	for (int i = n; i >= 2; i --){
		temp[i] = temp[i + 1] * node[i].a;
	}
	
	for (int i = 1; i <= n; i ++){
		INT res = node[i].b * temp[i + 1];
		ans += res;
	}
	
	print(ans);
	
	return 0;
}

动态最小生成树
链接:https://ac.nowcoder.com/acm/contest/9986/H
来源:牛客网

题目描述
小 Z 喜欢最小生成树。

小 Z 有一张 nn 个点 mm 条边的图,每条边连接点 u_i,v_iu
i

,v
i

,边权为 w_iw
i

。他想进行 qq 次操作,有如下两种类型:

修改第 xx 条边为连接点 y,zy,z ,边权为 tt ;
查询只用编号在 [l,r][l,r] 范围内的边,得到的最小生成树权值是多少。
由于修改和查询量实在是太大了,小 Z 想请你用程序帮他实现一下。

输入描述:
第一行,输入 n,m,q 。

接下来 m 行,输入 u_i,v_i,w_iu
i

,v
i

,w
i

接下来 q 行,读入 opt ,若 opt=1 则继续读入 x,y,z,t ,否则读入 l,r 。

输出描述:
对于每次询问,输出最小生成树权值。如果无解,输出 Impossible 。
示例1
输入
复制
5 5 3
1 2 1
2 3 2
3 4 3
4 5 4
1 5 3
2 1 4
2 2 5
2 1 5
输出
复制
10
12
9
备注:
数据保证:
1\le n\le 200,1\le m\le 30000,1\le q\le 30000,1\le u_i,v_i\le n,1\le w_i\le 1000001≤n≤200,1≤m≤30000,1≤q≤30000,1≤u
i

,v
i

≤n,1≤w
i

≤100000 。
1\le x\le m,1\le y,z\le n,1\le t\le 1000001≤x≤m,1≤y,z≤n,1≤t≤100000 。

涉及区间线段树,然后发现暴力也能过

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 2e2 + 10;
const int M = N * N;
const int mod = 998244353;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

int g[N][N], d[N];
int n, m, q;
bool st[N];

struct Edge{
	int a, b, w;
}edge[M];

void prim(){
	memset(d, 0x3f, sizeof d);
	memset(st, 0, sizeof st);
	
	d[1] = 0;
	for (int i = 1; i < n; i ++){
		int x = 0;
		for (int j = 1; j <= n; j ++){
			if (!st[j] && (x == 0 || d[j] < d[x]))   x = j;
		}
		
		st[x] = true;
		
		for (int j = 1; j <= n; j ++){
			if (!st[j])    d[j] = min(d[j], g[x][j]);
		}
	}
}

signed main(){
  	ios;
  	cin >> n >> m >> q;
  	for (int i = 1; i <= m; i ++){
  		int a, b, c;
  		cin >> a >> b >> c;
  		edge[i] = {a, b, c};
	  }
	
	for (int i = 1; i <= q; i ++){
		int op;
		cin >> op;
		
		if (op == 1){
			int x, y, z, t;
			cin >> x >> y >> z >> t;
			edge[x] = {y, z, t};
		}
		else{
			memset(g, 0x3f, sizeof g);
			for (int i = 1; i <= n; i ++)   g[i][i] = 0;
			
			int l, r;
			cin >> l >> r;
			if (l > r)   swap(l, r);
			
			for (int i = l; i <= r; i ++){
				int a = edge[i].a, b = edge[i].b, w = edge[i].w;
				g[a][b] = g[b][a] = min(g[a][b], w);
			}
			
			prim();
			
			bool flag = false;
			int ans = 0;
			
			for (int i = 2; i <= n; i ++){
				if (d[i] >= 0x3f3f3f3f3f3f3f3f){
					flag = true;
					break;
				}
				else   ans += d[i];
			}
			
			if (flag)    cout << "Impossible" << endl;
			else   cout << ans << endl;
		}
	}
	
	return 0;
}

贪吃蛇
链接:https://ac.nowcoder.com/acm/contest/9986/I
来源:牛客网

题目描述
无限增长的贪吃蛇小游戏:

在一个n*m的迷宫中,有一条小蛇,地图中有很多围墙,猥琐的出题者用“#”表示,而可以走的路用“.”表示,小蛇他随机出生在一个点上,出生点表示为“S”,他想抵达的终点表示为“E”,小蛇有一个奇怪的能力,他每走一格便会增长一格,即他走了一格后,他的尾巴不会缩回。

小蛇想知道他怎么到达他想去的地方,请你帮助他。

PS:每格长1米,贪吃蛇规定不能撞墙,不能咬自己的身体。
输入描述:
第一行:输入N,M;

第二行:输入S的坐标Xs,Ys,E的坐标Xe,Ye;

后面的N行:

每行输入M个数,描述每一行的情况。

输出描述:
输出一个数,小蛇到达终点的最短距离(单位:cm),若无法达到,输出-1
示例1
输入
复制
3 3
1 1 3 3
.#.
.#.

输出
复制
400
示例2
输入
复制
5 5
1 1 5 5
…###
.#…
.#.#.
.#.#.
…#.
输出
复制
1400
备注:
对于 100% 的数据:1\le n,m\le 1001≤n,m≤100 ,保证起点不是围墙。

bfs模板题

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 110;
const int M = 3 * N;
const int mod = 998244353;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

int n, m;
char s[N][N];
PII ss, tt;
bool st[N][N];
int dist[N][N];

int bfs(int startx, int starty){
	queue<PII> q;
	memset(dist, 0x3f, sizeof dist);
	dist[startx][starty] = 0;
	q.push({startx, starty});
	st[startx][starty] = true;
	
	while(q.size()){
		auto t = q.front();
		q.pop();
		
		int x = t.first, y = t.second;
		
		for (int i = 0; i < 4; i ++){
			int xx = x + dx[i], yy = y + dy[i];
			if (s[xx][yy] == '#')   continue;
			if (st[xx][yy])   continue;
			if (xx < 1 || xx > n || yy < 1 || yy > m)    continue;
			
		//	cout << xx << "---" << yy << endl;
			dist[xx][yy] = dist[x][y] + 1;
			st[xx][yy] = true;
		//	cout << dist[xx][yy] << endl;
			if (xx == tt.first && yy == tt.second)   return dist[xx][yy] * 100;
			
			q.push({xx, yy});
		}
	}
	
	return -1;
}

signed main(){
	cin >> n >> m;
	cin >> ss.first >> ss.second >> tt.first >> tt.second;
	
	for (int i = 1; i <= n; i ++){
		scanf("%s", s[i] + 1);
	}
	
	//cout << tt.first << "--" << tt.second << endl;
	cout << bfs(ss.first, ss.second)  << endl;
	
	return 0;
}

天空之城
链接:https://ac.nowcoder.com/acm/contest/9986/J
来源:牛客网

题目描述
天空之城有5个小镇,名字分别为Ada, Aed, Akk, Orz, Apq,他们也有相互的路径长度。

希达早已期盼着天空之城,如今她登上了天空之城,就想走遍天空之城的每一个城市,但是她希望自己走的路的长度越小越好,以节省体力和节约时间。

巴鲁同意了,但由于他是主力(男孩子嘛),需要帮希达计算出走遍所有城市的最短路径长度。

由于天空之城具有魔力,如果希达想再走一次自己之前走过的路,则她可以在这条路上不花费任何时间。

但是天空之城的城市太多了,他实在计算不过来,只得请你来帮帮忙了。

输入描述:
第一行,输入n,q, 表示有n个城市,q条边;

第二行,输入一个名字tmp,表示希达想要从tmp城市开始行走;

接下来q行,每行输入两个名字a,b和一个数字val, 表示a城市与b城市之间的距离为val.(注意可能有重边和自环)

输出描述:
帮助巴鲁计算出最短的路径长度,如果无法走遍所有城市,输出“No!”。
示例1
输入
复制
5 5
Orz
Ada Aed 5
Orz Ada 6
Apq Aed 8
Akk Apq 12
Aed Orz 3
输出
复制
28
说明
Ada->Aed->Orz->Aed->Apq->Akk
备注:
多组输入输出(以EOF结束),保证数据组数不超过 10 。

1 <= n <= 5000, 1 <= q <= 200000, 1 <= val <= 1e9. 每个城市的名字长度不超过10。

保证 \sum q \le 200000∑q≤200000 。

最小生成树

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
//using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int N = 4e5 + 10;
const int M = 3 * N;
const int mod = 998244353;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1); 

struct Edge{
	int a, b, w;
	bool operator<(const Edge &W)const{
		return w < W.w;
	}
}edge[N];

map<string, int> mp;
int n, q;
int p[N];
int edx;

void get_edx(string str){
	if (!mp[str])    mp[str] = ++ edx;
}

int find(int x){
	if (x != p[x])    p[x] = find(p[x]);
	return p[x];
}

signed main(){
	while(cin >> n >> q){
		memset(edge, 0, sizeof edge);
		mp.clear();
		edx = 0;
		for (int i = 1; i <= n; i ++)   p[i] = i;
		string temp;
		cin >> temp;
		
		for (int i = 1; i <= q; i ++){
			string str1, str2;
			int w;
			
			cin >> str1 >> str2;
			cin >> w;
			get_edx(str1);
			get_edx(str2);
			edge[i] = {mp[str1], mp[str2], w};
		}
		
		sort(edge + 1, edge + 1 + q);
		
		int ans = 0;
		int cnt = 0;
		for (int i = 1; i <= q; i ++){
			int a = edge[i].a, b = edge[i].b, w = edge[i].w;
			int pa = find(a), pb = find(b);
			
			if (pa != pb){
				ans += w;
				p[pa] = pb;
				cnt ++;
			}
		}
		
		if (cnt != n - 1)    cout << "No!" << endl;
		else cout << ans << endl;
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值