训练营的比赛已经开了3场了,也已经过年了,博客好像好久都没有更新过了,补一场的吧。
虽然说是基础训练营,但还是挺难的,感觉…
好了,不说了,开始吧。
B-括号
题意:就是让你找对应k的括号排列。正好有k个括号排列。
思路:这个题的数据范围比较大,如果按照它样例给出的办法,会超时。这个题当时也卡了很久,我的小朋友试出了办法,还是我太菜了。这个题,要是想到的话,就很快,想不到的话,就会绕弯。
它是左右()的数量相等的话,假如是n个的话,就按照n的平方的速度增加,所以我们先看比k小的最大平方数。然后看k-平方数差几个,然后从右边或者左边都行,假如从右边来说,就从右向左来找(,进行补齐。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
int judge(ll x)
{
if(x == 1)
return 0;
else if(x ==2)
return 1 ;
else if(x==3)
return 1;
else if(x%6!=1&&x%6!=5)
return 0 ;
int t =sqrt(x);
for(int i= 5; i <=t; i=i+6 )
if(x%i== 0||x%(i+2)==0)
return 0;
return 1 ;
}
int main ()
{
cin>>n;
if(n==0)
cout<<")("<<endl;//0的时候,不能输出空串
else if(n==1)
cout<<"()"<<endl;
else if(n==2)
cout<<"())"<<endl;
else if(n==3)
cout<<"()()"<<endl;
else
{
int p=sqrt(n);//找最大的出来的平方根
int q=n-p*p;//差的数量
int xx=q/p;//差的数量用几个p来补齐
int w=0;
if(q%p!=0)//不能整除的话,就单的一边来补齐
{
w=q%p;
}
for(int i=1;i<=p+xx;i++)//左边的话就是p+不能补齐的
{
cout<<'(';
}
for(int i=1;i<=p;i++)//单出来的一侧,从后向前
{
if(i==p-w+1){
cout<<'(';
}
cout<<')';
}
cout<<endl;
}
return 0;
}
F-对答案一时爽
题意:找出得分的最大值
思路:签到题,就是让一个人对就是最大的
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char a[N],b[N];
int main ()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
cin>>b[i];
}
int sum=0;
for(int i=1;i<=n;i++)
{
if(a[i]==b[i])
{
sum++;
}
}
cout<<n+sum<<" "<<0<<endl;
return 0;
}
I-限制不互素对的排列
题意:构造长度为n的序列,正好有k对相邻的数gcd>1。
思路:gcd>1,就是相邻的不能是素数,因为1~n的数,只能用一次,偶数不可能是素数,所以我们可以利用偶数来排列,3和6,虽然不是偶数,但是按照 6 3 来排列的话,也可以达成一对,因为6是偶数,3是素数,所以要按照6 3来排列。到达k对之后,剩下的可以按照从1开始,没有利用的数相邻排列就可以了,因为剩下的都是素数了。但如果n小于6的话,n/2就是偶数的个数等于n的话,就无法构造成功。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
bool vis[N];
int a[N];
int main ()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,k;cin>>n>>k;
if(n<6&&k==n/2)//特判
{
cout<<-1<<endl;
}
else
{
int cnt=0;
for(int i=2;i<=n;i=i+2)
{
if(i!=6)
a[++cnt]=i;//不算6,把小于n的偶数存进数组
}
a[++cnt]=6;a[++cnt]=3;//将6 3分别按顺序存进数组
for(int i=1;i<=k+1;i++)
{
cout<<a[i]<<" ";
vis[a[i]]=1;/输出k对,就是到k+1个数字,然后标记一下
}
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
cout<<i<<" ";//将剩下的数字排列输出,因为相邻的数字gcd一定=1
}
cout<<endl;
}
return 0;
}
J-一群小青蛙呱蹦呱蹦呱
题意:就是有一个以素数为公差的等比数列,然后都从1开始,进行标记,没有被标记过的数字的lcm是多少?
思路:这题是数论,数论渣渣,看了好几个题解,理解个大概吧,试一试吧,吃掉了所有所有的素数的倍数,剩下的就是含有大于两个质因子的数了,所以求lcm,其实就是求这些质因子的最大次幂,让幂次最大的话,如果是2的话,那么最大的那个数一定是2^k * 3=n,所以k这个最大的幂次就是log2^(n/3),为什么呢,因为每次最大就是让这个数利用2最多次,然后左边最大就是右边最大,那么最大就是n了,那么素数是从2 3 5开始的,最大的数就是幂次最多,然后*最小的数,如果>2的话,就是当前数字pi^k * 2=n,所以k=logpi^(n/2)。其实换句话来说,就是 让pi^k 最大,就是k最大,等式右边就是n/一个数,你得让那个数尽可能的小,所以是2 或者 3。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=8e7+5;
const ll mod=1e9+7;
int p[N/8];
bool vis[N];
int cnt=0;
int n;
ll ksm(int a,int b){//快速幂
ll ans=1,t=a;
while(b)
{
if(b&1)
ans=ans*t%mod;
t=t*t%mod;
b>>=1;
}
return ans;
}
ll calc(int x){//求log的过程
if (x==2)//有点细节,就是得用floor来计算
return ksm(2,floor(log(1.0*n/3)/log(1.0*2)));
return ksm(x,floor(log(1.0*n/2)/log(1.0*x)));
}
int main ()
{
//ios::sync_with_stdio(false);
cin>>n;
ll ans=1;
memset(vis,1,sizeof vis);
for(int i=2;i<=n/2;i++)//范围太大,n/2的范围就够用了
{
// cout<<ans<<endl;
if(vis[i])
{
p[cnt++]=i;//没被标记,就是素数
// cout<<ans<<endl;
ans=(ans*calc(i))%mod;
//cout<<ans<<endl;
}
for(int j=0;j<cnt&&i*p[j]<=n/2;j++)
{
vis[i*p[j]]=0;//线性筛
if(i%p[j]==0)
break;
}
//cout<<ans<<endl;
}
if(ans==1)
cout<<"empty"<<endl;//判空
else
cout<<ans<<endl;//答案
return 0;
}