牛客0211题解

A-欧几里得

题意

现在,如果已知 gcd(a,b) 共递归了 n次,求所有可能的a,b中满足a>b>=0且a+b最小的一组的a与b之和。意思就是递归n次b 就为0 ,比如说,n为0是gcd(1,0)答案为1,如果n为1是 gcd(2,1)为 3 , 如果是 2 就是gcd(3,2) yi 次边为 gcd(2,1)在一次成(1,0)了

思路

通过上满题的描述就可看出来最小的时候都是斐波那契数列, gcd fn+1 ,f n

代码

#include<iostream>
using namespace std;
int main()
{
	long long  f[1000];
	int n;
	
	f[1]=1;
	f[2]=2;
	for(int i=3;i<=100;i++) 
	 f[i]=f[i-1]+f[i-2];
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n;
		if(n==0)
		 cout<<"1"<<endl; 
		else
		
		  cout<<f[n]+f[n+1]<<endl;
	}
	return 0;
	
}

B-括号序列

题意

给一个括号序列问是否是合法的,(){} 是合法的,{()} 也是合法的

思路

利用堆栈,如果是左括号就进栈,然后遇到右括号的时候,先判断堆栈是否是空的如果堆栈是空的 那肯定就不合法了,如多堆栈不是空的 ,就取栈定元素,然后删除栈顶,判断栈顶的左括号时候和现在的右括号匹配,如果匹配继续,如果不匹配退出,最后判断了 还有看堆栈时候是空的,不是空的也不行,因为不是空的说明还有多余的左括号

代码

#include<iostream>
#include<string>
#include<cstring>
#include<stack>
using namespace std;
int main()
{
	string str;
	cin>>str;
	int f=1;
	stack<char>s;
	for(int i=0;i<str.length();i++)
	{
		if(str[i]=='('||str[i]=='['||str[i]=='{')
		 s.push(str[i]);
		else
		 {
		 	if(s.empty())
		 	{
		 		f=0;
		 		break;
		 	}
		 	else
		 	 {
		 	 	char a=s.top();
		 	 	s.pop();
		 	 	if(str[i]==')')
		 	 	 if(a!='(')
		 	 	 {
		 	 	 	f=0;
		 	 	 	break;
		 	 	 }
		 	 	 if(str[i]=='}')
		 	 	  if(a!='{')
		 	 	 {
		 	 	 	f=0;
		 	 	 	break;
		 	 	 }
		 	 	 if(str[i]==']')
		 	 	  if(a!='[')
		 	 	 {
		 	 	 	f=0;
		 	 	 	break;
		 	 	 }
		 	 }
		 }
	}
	if(!s.empty()) 
	 f=0;
	if(f)
	 cout<<"Yes"<<endl;
	else
	 cout<<"No"<<endl;
	return 0;
}
	

C.字段乘积

提议

给一个n和k n 是数组的长度,然后给你一个数组,让你求 连续的长度为k 的字段乘积的最大值 还要模一个数

思路

尺取法,固定l 不动r 加加,当长度为k 时更新最大值 ,然后把a[l]除去,这里用到乘他的逆元,然后l 加加,继续重复上述操作,要注意的是 如果 扫描到0了 就要直接把l 移动到0前面,

代码

#include<iostream>
#include<algorithm> 
using namespace std;
const int mod=998244353;
typedef long long ll;
ll sum=1;
ll maxn=0;
ll a[200010];
ll quickpow(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
		 ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans;
}
int main()
{
	ll n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	 cin>>a[i];
	ll r=1,l=1;
	while(r<=n)
	{
		if(a[r]) //扫到的不是 0的情况
		{
			sum=(sum*a[r])%mod;
			if((r-l+1)%k==0)//长度为k时判断
			{
				if(sum>maxn) maxn=sum;
				sum=sum*quickpow(a[l],mod-2)%mod;//本来要除a[l]但wa 得乘al的逆元也就是然后根据费马小定理
				//逆元就是这样的求的 
				l++;
			} 
		} 
		else
		{
			l=r+1;
			sum=1;
		}//如果扫到0了就直接跳过 sum  也得为1 
		r++;
		 
	}
	cout<<maxn<<endl;
	return 0; 
	
	
}
 

D-字段异或

题意

给一个n为数列的长度,然后 对一个字段[l,r]求异或和,为 a[l]异或a【l+1】异或a[l+2]一直异或到 a[r],统计 异或和为0 的子段个数,只要 l 和r 有一个是不同,这样就是不同的字段

思路

[1,l−1]⊕[1,r]=[l,r],所以如果【l,r】为0,那么 l-1的前缀异或和就和r 的前缀疑惑和相等,所以就求前缀异或和,然后再map 维护

代码

#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
int a[200010],b[200010];
map<ll,ll>mp;
int main()
{
	int n;
	ll ans=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		b[i]=b[i-1]^a[i];//求前缀异或和
		if(b[i]==0) ans++;//如果是 1,i 异或和为0也是满足要求的嘛
		ans+=mp[b[i]];
		mp[b[i]]++;//map 好像可以统计 b[i]的次数,先是为0,然后没出现一次就加1 
	}
	cout<<ans<<endl;
	return 0; 
}
发布了7 篇原创文章 · 获赞 0 · 访问量 95

猜你喜欢

转载自blog.csdn.net/xgx984826498/article/details/104358387