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