NOI马拉松 5.5
NOI马拉松 5.5
比赛情况
这次比赛时间很长,总共7个半小时。做题策略也比较奇怪。
最开始的两个小时在看T4,T5,T5理解完题意后发现20分是好写的,之后就去爆肝T4了。T4先是写了20分的暴力,交完暴力之后因为\(noi\ Linux\)这个垃圾系统自带的Firefox不是最新的,看不到提交记录,我也不知道问题出在哪里。还有就是还是很不习惯\(Linux\)下的调试和对拍的过程,很多时间都用在整这个东西上了。
上午出成果非常少,很早的时候T4就想到了正解,但到11点半的时候我还是只有25分,20分T4暴力,5分T2暴力,原因是T4在算质因数的时候直接写到了\(n\)而不是\(\sqrt{n}\),但一直没看出来,整个心态就很崩。中午就恰饭去了。
下午回来的时候又想了一遍,这个算法的复杂度显然没有问题,处理的次数也不会太多的,不应该不对啊。然后看了一下运行的时间,发现在预处理的时候就已经跑了1s了,发现质因数分解写成了\(O(n)\)。然后改完之后直接交了,就A了。
然后的时间就开始各种写暴力,但没有骗分,或者说不会骗分,一个没骗上。T1输出\(Yes\)的50分没拿直接自裁吧。T3有个13分的听到ztw的说法后骗到了。然后就结束了。
主要问题就是在码T4的时候出现了重大的技术性失误(我就是纯脑瘫,心态比较崩。对,T1还是见过的题目,那一场arc的这个题我还写了。
赛后总结
这次的T4正解思路不算特别好想,但是也没有用到特别奇怪的东西,想到还是挺好的。
T4
题意
给定\(N\)个正整数,你要在这里找出一个二元组\((a_i,a_j)\),满足\(\gcd(a,b)=1\),且\(998244353\times a_i + a_j\)的值最小。\((N \leq 2 \times 10^5, a_i \leq 2 \times 10^6)\)
算法分析
由于\(a_i\)的值和前面的系数差异非常大,所以比较自然的想法是对\(a\)进行排序,之后尽量找到\(a_i\)小的解。这一部分可以转化成考虑在\(i\)之后的\(n-i\)个数中有没有和\(a_i\)不互质的数。这个东西直接维护的话不是很好维护,我们可以考虑容斥。对\(a_i\)做唯一分解。
我们可以发现指数\(\alpha\)是没有影响的,我们可以只考虑\(a_i\)的次数为\(1\)或\(0\)的\(2^s-1\)个因数。这些数可以用\(V_i\)这个\(s\)位二进制数表示,在预处理的时候对这些数加一。询问的时候考虑计算
这个值就是在\(i\)这一位后面的和\(S\)不互质的数的个数。判断是不是等于\(n-i\),如果不是说明是有解的,暴力求解就可以了。总复杂度应该是\(O(n\sqrt{n})\)的。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int mn=2e5+6,mp=2e6+7;
int n,a[mn],p[mp],c[10];
LL vis[mp];
void get_prime()
{
for(int i=2;i<mp;++i) {
if(!p[i]) p[++p[0]]=i;
for(int j=1;j<=p[0]&&i*p[j]<mp;++j) {
p[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
inline int gcd(int a,int b)
{
if(!b) return a;
return gcd(b,a%b);
}
int main()
{
freopen("cprime.in","r",stdin);
freopen("cprime.out","w",stdout);
scanf("%d",&n);
get_prime();
for(register int t=1;t<=n;++t) {
scanf("%d",a+t);
}
sort(a+1,a+n+1);
for(int t=1;t<=n;++t) {
int tmp=a[t];c[0]=0;
int sqr=sqrt(tmp);
for(int j=1;p[j]<=sqr;++j) {
if(tmp%p[j]==0) {
c[++c[0]]=p[j];
while(tmp%p[j]==0) tmp/=p[j];
}
}
if(tmp!=1) c[++c[0]]=tmp;
for(register int i=1;i<(1<<c[0]);++i) {
tmp=1;
for(register int j=0;j<c[0];++j) if((i>>j)&1) {
tmp*=c[j+1];
}
vis[tmp]++;
}
}
for(register int t=1;t<=n;++t) {
int tmp=a[t],flag,sqr=sqrt(tmp);
LL siz=0;c[0]=0;
for(int j=1;p[j]<=sqr;++j) {
if(tmp%p[j]==0) {
c[++c[0]]=p[j];
while(tmp%p[j]==0) tmp/=p[j];
}
}
if(tmp!=1) c[++c[0]]=tmp;
for(int i=1;i<(1<<c[0]);++i) {
tmp=1;
for(int j=0;j<c[0];++j) if((i>>j)&1) {
tmp*=c[j+1];
}
vis[tmp]--;
}
for(register int i=1;i<(1<<c[0]);++i) {
tmp=1;flag=0;
for(register int j=0;j<c[0];++j) if((i>>j)&1) {
tmp*=c[j+1];flag^=1;
}
if(flag) siz+=vis[tmp];
else siz-=vis[tmp];
}
if(siz!=n-t) {
for(int i=t+1;i<=n;++i) {
if(gcd(a[t],a[i])==1) {
printf("%d %d\n",a[t],a[i]);
return 0;
}
}
}
}
puts("-1");
return 0;
}

浙公网安备 33010602011771号