牛客练习赛67

牛牛爱字符串
链接:https://ac.nowcoder.com/acm/contest/11643/A
来源:牛客网

牛牛在玩字符串。
牛牛得到了一个字符串(可能含有空格),他希望在这些字符串中提取出数字。
例如:a1b23c456d007890中可以提取出1, 23, 456, 7890共4个数字。

现在,他得到了一个长度高达1000的字符串,请你帮他提取出所有的数字。

输入描述:
本题有多组数据。
输入一个字符串S。
输出描述:
输出提取出的所有数字,相邻两个数字用一个空格隔开。
不包含数字的时候输出空行
注意,你输出的数不能含有前导0。
示例1
输入
复制
u1s1qs
1a2b3c4d5e006d
a1b23c456d007890
2333
kur1su
alan0233
输出
复制
1 1
1 2 3 4 5 6
1 23 456 7890
2333
1
233
备注:
数据保证\sum length(S)\le 100000∑length(S)≤100000,字符串可能含有空格。

需要注意的点有开头结尾,还有中间只有一个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;

#define gt(x) x = read()
#define int  long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#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 out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2e6 + 10;
const int M = 2e7 + 10;
const int mod = 77797;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);


signed main(){
	string str;
	while(getline(cin, str)){
	
	
	bool flag = false;
	for (int i = 0; i < str.size(); i ++){
		if (str[i] >= '1' && str[i] <= '9'){
			cout << str[i];
			flag = true;
		}
		else if (str[i] == '0' && flag){
			cout << str[i];
		}
		else if (str[i] == '0' && !(str[i + 1] >= '0' && str[i + 1] <= '9')){
			cout << "0 ";
		}
		else if (flag){
			flag = false;
			cout << " ";
		}
	}
	
	cout << endl;
	}
	
	
	
	return 0;
}

牛牛爱位运算
链接:https://ac.nowcoder.com/acm/contest/11643/B
来源:牛客网

题目描述
牛牛正在学习位运算
他刚刚理解&的用法(and),准备趁热打铁,做做下面这题:
给定一个长度为n的序列a,你需要从中挑出任意多个(可以0个)数,使得他们&起来值最大。
看起来挺简单的,可是牛牛就是不会做。
比如说选出五个数1,3,5,7,9,他们&起来的值就是1&3&5&7&9=1
输入描述:
第一行,输入一个数T,表示数据组数。
第2~(T+1)行,每行读入一个数n,接下来读入n个数,第i个数表示a_ia
i


输出描述:
对于每一组数据,你需要输出&的最大值。
示例1
输入
复制
2
1 5
2 5 5
输出
复制
5
5
说明
第一组数据,显然取5是最优的;
第二组数据,可以取两个5,5&5=5是最优的。
备注:
数据保证1\le T\le 100000, 1\le a_i,n\le 10^51≤T≤100000,1≤a
i

,n≤10
5
,并且\sum n \le 10^6∑n≤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;

#define gt(x) x = read()
#define int  long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#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 out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2e6 + 10;
const int M = 2e7 + 10;
const int mod = 77797;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int a[N];

signed main(){
	int T;
	gt(T);
	
	while(T --){
		int n;
		scanf("%lld", &n);
		
		int maxd = 0;
		for (int i = 1; i <= n; i ++){
			scanf("%lld", &a[i]);
			maxd = max(maxd, a[i]);
		}
		
		cout << maxd << endl;
	}
	
	return 0;
}

牛牛爱博弈
链接:https://ac.nowcoder.com/acm/contest/11643/C
来源:牛客网

题目描述
牛牛和牛妹玩博弈游戏。
牛牛:我们来玩取石子游戏。一共有n堆石子,每个人每次可以取1或2颗石子,谁取走了最后一颗石子就算谁获胜。
牛妹:这游戏太无聊了。
牛牛:那改一改。一共有n堆石子,每个人每次可以取1,2,4,8,…2^k2
k
颗石子,谁取走了最后一颗石子就算谁获胜。
牛妹:好的,你先开始取吧。
牛牛心里知道自己是否有必胜策略,但他想来考考你。
因为牛牛和牛妹很爱玩这种游戏,所以本题有多组数据。
(注:牛牛叫\color{grey}{Alan}Alan,牛妹叫\color{black}{F}\color{red}{rame}Frame.)

输入描述:
第一行,输入数据组数T。
接下来T行,每行一个数n。

输出描述:
对于每一组数据,
如果牛牛必胜,则输出“Alan”(不含引号);
如果牛妹胜,则输出“Frame”(不含引号)。
(PS:牛牛叫 Alan ,牛妹叫 Frame )

示例1
输入
复制
3
1
2
3
输出
复制
Alan
Alan
Frame
说明
当n=1时,牛牛直接取1颗石子即可获胜。
当n=2时,牛牛直接取2颗石子即可获胜。
当n=3时,显然牛牛论怎么取,牛妹都可以获胜。
示例2
输入
复制
3
17
18
19
输出
复制
Alan
Frame
Alan
备注:
数据保证1\le T\le 1000,1\le n\le 2\times 10^91≤T≤1000,1≤n≤2×10
9

在先手赢得概率更大的前提下,蒙一手

#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;

#define gt(x) x = read()
#define int  long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#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 out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2e6 + 10;
const int M = 2e7 + 10;
const int mod = 77797;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int a[N];

signed main(){
	int T;
	gt(T);
	
	while(T --){
		int n;
		scanf("%lld", &n);
		
		if (n % 3 == 0){
			cout << "Frame" << endl;
		}
		else  cout << "Alan" << endl;
	}
	
	return 0;
}

牛妹爱数列
链接:https://ac.nowcoder.com/acm/contest/11643/D
来源:牛客网

题目描述
牛妹正在玩一个数列
他手里有一个长度为n的序列a,保证它是一个01序列,并执行以下两种操作:
1.单点修改:将位置x上的数翻转(0变1,1变0);
2.前缀修改:将位置1~x上的数翻转(每个数都0变1,1变0)。
他现在想要最小化翻转次数,使得数列上的所有数都变为0。

输入描述:
第一行,输入一个数n。
第二行,输入n个数,第i个数表示a_ia
i


输出描述:
输出最小翻转次数。
示例1
输入
复制
10
1 0 1 1 0 0 0 1 0 0
输出
复制
3
说明
样例解释:
第一次使用(1)操作, 把2改掉: 1 1 1 1 0 0 0 1 0 0
第二次使用(2)操作, 把1-4全部改掉: 0 0 0 0 0 0 0 1 0 0
第三次使用(1)操作, 把8改掉: 0 0 0 0 0 0 0 0 0 0
备注:
数据保证1\le n\le 10^5,0\le a_i\le 11≤n≤10
5
,0≤a
i

≤1。

涉及序列的肯定要考虑动态规划啊,人傻了,前i个序列,要么都是1,要么都是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;

#define gt(x) x = read()
#define int  long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#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 out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2e6 + 10;
const int M = 2e7 + 10;
const int mod = 77797;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int f[N][2];

signed main(){
	int n;
	scanf("%lld", &n);
	
	for (int i = 1; i <= n; i ++){
		int x;
		scanf("%lld", &x);
		if (x){
			f[i][1] = min(f[i - 1][1], f[i - 1][0] + 1);
			f[i][0] = min(f[i - 1][1] + 1, f[i - 1][0] + 1);
		}
		else{
			f[i][1] = min(f[i - 1][1] + 1, f[i - 1][0] + 1);
			f[i][0] = min(f[i - 1][0], f[i - 1][1] + 1);
		}
	}
	
	cout << min(f[n][0], f[n][1] + 1) << endl;
	
	return 0;
}

牛妹游历城市
链接:https://ac.nowcoder.com/acm/contest/11643/E
来源:牛客网

题目描述
最近,牛妹天天宅在家里,真是憋死人了。他决定出去旅游。
牛妹现在正在1号点(自己家里),他决定前往n号点(牛妹想去的地方),中途可以多次经过1~n号点。
现在,已知每个点都有个权值a_ia
i

,如果a_i & a_j ≠0a
i

&a
j



=0,则i号点和j号点之间连有一条双向边,权值为lowbit(a_i & a_j)lowbit(a
i

&a
j

)。
他想要最小化自己的行走距离,但是他计算不出来qaq。相信全牛客最聪明的你一定会吧!
Tips:
&&是位运算中and的意思,lowbit(n)的值是最大的2^x2
x
,满足2^x | n2
x
∣n。
例如lowbit(5)=lowbit((101)_2)=1,\ lowbit(8)=lowbit((1000)_2)=8lowbit(5)=lowbit((101)
2

)=1, lowbit(8)=lowbit((1000)
2

)=8。
输入描述:
本题有多组数据。
第一行,输入一个数T,表示数据组数。
接下来2*T行,先输入一个数n,再输入n个数,第i个数表示a_ia
i


输出描述:
对于每组数据,输出最小的行走距离。
如果无法从1号点到达n号点,则输出“Impossible”(不含引号)。
示例1
输入
复制
2
6
2 3 5 8 13 21
12
1 2 3 4 5 6 7 8 9 10 11 12
输出
复制
3
5
示例2
输入
复制
5
3
1 2 3
4
177 188 199 211
2
1 2
4
1 1 1 1
5
1 2 4 8 16
输出
复制
1
1
Impossible
1
Impossible
备注:
数据保证1\le T\le 5, 1\le n\le 10^5, 1\le a_i < 2^{32}1≤T≤5,1≤n≤10
5
,1≤a
i

<2
32

这道题人傻了,涉及到二进制的数枚举的一定是二进制的每一位,建立虚拟源点是非常必要的一种方法,二进制的每一位建立一个虚拟源点,因为求得是最短路,多建的那些也许本来不存在的边一定不会被用到,所以答案是对的走的边是lowbit,也就是最短边

#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;

#define gt(x) x = read()
#define int  long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#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 out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2e6 + 10;
const int M = 2e7 + 10;
const int mod = 77797;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int h[N], e[N], w[N], ne[N],idx;
int n;
int dist[N];
bool st[N];
int a[N];

void add(int a, int b, int c){
	e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

void dijkstra(){
	memset(st, 0, sizeof st);
	memset(dist, 0x3f, sizeof dist);
	dist[1] = 0;
	priority_queue<PII, vector<PII>, greater<PII>> heap;
	heap.push({0, 1});
	
	while(heap.size()){
		auto t = heap.top();
		heap.pop();
		
		int ver = t.second, distance = t.first;
		
		if (st[ver])   continue;
		st[ver] = true;
		
		for (int i = h[ver]; ~i; i = ne[i]){
			int j = e[i];
			
			if (dist[j] > dist[ver] + w[i]){
				dist[j] = dist[ver] + w[i];
				heap.push({dist[j], j});
			}
		}
	}
}

//建立虚拟原点太有用了,凡是涉及二进制的数,最后会发现枚举的都是他们的位数。

signed main(){
	int T;
	scanf("%lld", &T);
	while(T --){
		idx = 0;
		memset(h, -1, sizeof h);
		
		scanf("%lld", &n);
		
		for (int i = 1; i <= n; i ++)
		scanf("%lld", &a[i]);
		
		for (int i = 1; i <= n; i ++){
			for (int j = 0; j < 32; j ++){
				if (a[i] >> j & 1){
					add(i, n + j + 1, 1 << j);
                    //一定要把int型的数字变成long long姓
					add(n + j + 1, i,0);
				}
			}
		}
		
		dijkstra();
		
		if (dist[n] == 0x3f3f3f3f3f3f3f3f)    cout << "Impossible" << endl;
		else   cout << dist[n] << endl;
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值