前两天参加了多校第三场,感慨就是菜是真的菜,代码写得还不规范,碰上一个想要卡时间复杂度的出题人直接GG。
说到G,牛客多校第三场的G题还不会,希望放到本篇里面继续学习。
2020/7/20目标:
牛客多校第四场rank:top500
完成B,F
B
解读数学表达式,再加上少许尝试,发现答案为pow(c,cnt)
其中cnt是n的质因数的个数
需要打表
TLE了两次
F
题意:
已知AB//CD所在直线,知道AC,AD,BC,BD的值,问确定CD的顺序。
连接AD,AC,BC,BD
又由最简单的三角形两边之和大于第三边
发现:AD+BC>AC+BD=>顺序为CD
反之顺序为DC
H
题意:
从1到n中最多能取出几对最大公因数不为1的数对
我的思考:
打表找出n/2到n中的素数个数m,(n-m-1)/2即为数对数。
困难:
用什么构造方法可以构造该数对,尝试了dp(后来自己证明了是错的),贪心(代码就不发上来了)
题解:
还是构造的方法
首先应该考虑有那些数不能参与匹配。显而易见1和大于n/2的素数一定没有匹配对象,可以直接忽略。
接下来考虑剩下的素数,倒序枚举每个素数p,找出所有未匹配的p的倍数,并且记下总数。 如果总数是偶数,那么这些数就可以完美两两匹配;否则留下2*p(2的倍数最为常用,可以用于应对最后剩下的数),匹配其余的数。
最后只会留下一堆偶数,而它们两两都可以随意匹配。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
bool u[maxn];//==1为素数
int su[maxn];
int suc[maxn];
void prepare(int n)
{
int num=1;
memset(u,true,sizeof(u));
for(int i=2;i<=n;i++)
{
if(u[i]) su[num++]=i;
for(int j=1;j<num;j++)
{
if(i*su[j]>n) break;
u[i*su[j]]=false;
if(i%su[j]==0) break;
}
}
for(int i=2;i<n;i++)
{
if(u[i]==1)
{
suc[i]=suc[i-1]+1;
}
else suc[i]=suc[i-1];
}
}
bool leap[maxn];
int main()
{
int T;
scanf("%d",&T);
prepare(2e5+1);
while(T--)
{
int n;
scanf("%d",&n);
{
int cnt=0;
memset(leap,0,sizeof leap);
int ans=n-1-(suc[n]-suc[n/2]);
printf("%d\n",ans/2);
stack<int> s;
for(int i=n/2;i>=2;i--)
{
stack<int> ss;
if(u[i]==1)
{
int cnt=0;
for(int j=1;j<=n/i;j++)
{
if(leap[i*j]==0)
{
cnt++;
}
}
if(cnt%2==0)
{
for(int j=1;j<=n/i;j++)
{
if(leap[i*j]==0)
{
leap[i*j]=1;
ss.push(i*j);
}
if(ss.size()==2)
{
cout<<ss.top();
ss.pop();
cout<<" "<<ss.top()<<endl;
ss.pop();
}
}
}
if(cnt%2==1)
{
s.push(2*i);
leap[2*i]=1;
for(int j=1;j<=n/i;j++)
{
if(leap[i*j]==0)
{
leap[i*j]=1;
ss.push(i*j);
}
if(ss.size()==2)
{
cout<<ss.top();
ss.pop();
cout<<" "<<ss.top()<<endl;
ss.pop();
}
}
leap[2*i]=0;
}
}
}
//cout<<endl;
}
}
}
本次多校难度较高,区分度也比较小,我队做出来2题的时间还是比较快的,但是由于罚时未能进入前500,(主要我的两个TLE和两个WA),以后还要注意。
抽空补I题。