牛客练习赛67 (A、B、C、D、E)

A、 牛牛爱字符串

思路

getline读取,把非数字的字符跳过,字符串处理数字,然后删除前导 0 0 0
注意特判一下 0 , 00 , 000 0,00,000 0,00,000 这种情况

参考代码

#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;

signed main() {
	#ifndef ONLINE_JUDGE
		//freopen("in.txt", "r", stdin);
		//freopen("out.txt","w",stdout);
	#endif
	string s;
	while(getline(cin,s)){
		for(int i = 0;i < s.size();++i){
			if(s[i]>='0'&&s[i]<='9'){
				string p="0";
				bool f =0;
				while(i<s.size()&&s[i]>='0'&&s[i]<='9'){
					if(s[i]!='0')f = 1;
					if(f)p.push_back(s[i]);
					++i;
				}
				--i;
				if(p.size()>1){
					for(int i = 1;i < p.size();++i)cout<<p[i];
					cout<<" ";
				}else cout<<p<<" ";
			}
		}
		cout<<endl;
	}
	return 0;
}

B、 牛牛爱位运算

思路

对于数 x x x ,它 & 上任何一个数都不会使它变大,所以取个最大值即可。

参考代码

#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;

signed main() {
	#ifndef ONLINE_JUDGE
		//freopen("in.txt", "r", stdin);
		//freopen("out.txt","w",stdout);
	#endif
	int t;cin>>t;
	while(t--){
		int n;cin >> n;
		int ans = -1;
		for(int i = 1;i <= n;++i){
			int x;cin >>x;
			ans = max(ans,x);
		}
		cout<<ans<<endl;
	}
	return 0;
}

C、 牛牛爱博弈

思路

模拟一下,可以发现一个规律,以 3 3 3 为周期,从1开始,赢赢输赢赢输赢赢输。

参考代码

#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;

signed main() {
	#ifndef ONLINE_JUDGE
		//freopen("in.txt", "r", stdin);
		//freopen("out.txt","w",stdout);
	#endif
	int t;
	cin >>t;
	while(t--){
		int n;cin >>n;
		bool f = 0;
		n %= 3;
		if(n==0)f = 0;
		else f = 1;
		if(f)cout<<"Alan\n";
		else cout<<"Frame\n";
	}
	return 0;
}

D、 牛妹爱数列

思路

简单 DP, d p [ i ] [ 0 ] dp[i][0] dp[i][0] 表示把前 i i i位都变成 0 0 0 需要的最小代价, d p [ i ] [ 1 ] dp[i][1] dp[i][1] 表示把前 i i i位都变成 1 1 1 需要的最小代价。
转移的方程:
如果 a [ i ] = = 1 a[i]==1 a[i]==1 d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + 1 ) + 1 ; d p [ i ] [ 1 ] = m i n ( d p [ i − 1 ] [ 0 ] + 1 , d p [ i − 1 ] [ 1 ] ) ; dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1) + 1; dp[i][1] = min(dp[i-1][0]+1,dp[i-1][1]); dp[i][0]=min(dp[i1][0],dp[i1][1]+1)+1;dp[i][1]=min(dp[i1][0]+1,dp[i1][1]);
如果 a [ i ] = = 0 a[i]==0 a[i]==0 : d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + 1 ) ; d p [ i ] [ 1 ] = m i n ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] ) + 1 ; dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1); dp[i][1] = min(dp[i-1][1],dp[i-1][0]) + 1; dp[i][0]=min(dp[i1][0],dp[i1][1]+1);dp[i][1]=min(dp[i1][1],dp[i1][0])+1;

参考代码

#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
int a[man],dp[man][2];

signed main() {
	#ifndef ONLINE_JUDGE
		//freopen("in.txt", "r", stdin);
		//freopen("out.txt","w",stdout);
	#endif
	int n;scanf("%d",&n);
	for(int i = 1;i <= n;++i){
		scanf("%d",&a[i]);
	}
	for(int i = 1;i <= n;++i){
		if(a[i]){
			dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1) + 1;
			dp[i][1] = min(dp[i-1][0]+1,dp[i-1][1]);
		}else{
			dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1);
			dp[i][1] = min(dp[i-1][1],dp[i-1][0]) + 1;
		}
	}
	printf("%d\n",min(dp[n][0],dp[n][1]+1));
	return 0;
}

E、牛妹游历城市

思路

首先暴力建图肯定不行的,直接被卡死。
那么想如何优化。
首先我们可以按位操作,把32位看成点,然后对每个点拆点。
即:对于第 i i i 位(二进制) 有两个点, i 1 i_1 i1(入点)和 i 2 i_2 i2(出点) , i 1 i_1 i1 i 2 i_2 i2 连一个边,边权为 2 i 2^i 2i
然后对于输入的 a [ i ] a[i] a[i],如果当前 a [ i ] a[i] a[i] 在第 x x x 位(二进制)是 1 1 1,那么这个点向 x 1 x_1 x1 连一条边权为 0 0 0 的边, x 2 x_2 x2 向该点连一条边权为 0 0 0 的边。
最后跑一遍最短路即可。
正确性:
题目要求的是如果 a i a_i ai & a j a_j aj ! = 0 != 0 !=0,那么这两个点之间可以连边,边权为 l o w b i t ( a i lowbit(a_i lowbit(ai& a j ) a_j) aj)
我们这么建图如何保证所走的边的边权是两个点的 l o w b i t ( a i lowbit(a_i lowbit(ai& a j ) a_j) aj) 呢。
首先假设存在一条最短路: u u u 指向 v v v 的,以上建图方式,他们的边权一定是 l o w b i t ( a i lowbit(a_i lowbit(ai& a j ) a_j) aj) 吗?答案是肯定的,假设我们最短路已经搜到 u u u 这里了,从 u u u 开始去找其他的点,它要走到 v v v,那么它下一步的点一定是 u , v u,v u,v 点权二进制位数都有的,且是最低位(符合最短路贪心的思路)。

参考代码

#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
struct node{
	int v;
	ll w;
	bool operator < (const node &a)const{
		return w > a.w;
	}
};
vector<node>sp[man];
ll a[man];

void add(int u,int v,ll w){
	sp[u].push_back(node{v,w});
}
priority_queue<node>q;
ll dis[man];
bool vis[man];int n;
void dij(int s,int num){
	for(int i = 1;i <= num;++i)dis[i] = 1e18,vis[i] = 0;
	dis[s] = 0;
	q.push(node{1,0});
	while(q.size()){
		node tp = q.top();
		q.pop();
		if(vis[tp.v])continue;
		vis[tp.v] = 1;
		for(auto it:sp[tp.v]){
			int v = it.v;
			ll w = it.w;
			if(vis[v])continue;
			if(dis[v]>dis[tp.v] + it.w){
				dis[v] = dis[tp.v] + it.w;
				q.push(node{v,dis[v]});
			}
		}
	}
	if(dis[n]==1e18)printf("Impossible\n");
	else printf("%lld\n",dis[n]);
}


signed main() {
	#ifndef ONLINE_JUDGE
		freopen("in.txt", "r", stdin);
		//freopen("out.txt","w",stdout);
	#endif
	int t;scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i = 1;i <= n;++i){
			scanf("%lld",&a[i]);
		}
		int num = n+1;
		for(int i = 0;i <= 32;++i)add(num+i,num+40+i,(1ll<<i));
		for(int i = 1;i <= n;++i){
			for(int j = 0;j <= 32;++j){
				if((a[i]>>j)&1){
					add(i,num+j,0);
					add(num+40+j,i,0);
				}
			}
		}
		dij(1,num+100);
		for(int i = 1;i <= num+100;++i){
		//	cout<<"u:"<
		//	for(auto it:sp[i])cout<
		//	cout<
			sp[i].clear();
		}
	}
	return 0;
}

你可能感兴趣的:(牛客,图论)