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\)做唯一分解。

\[a_i = p_1^{\alpha_1} \times p_2^{\alpha_2} \times \cdots \times p_s^{\alpha_s}\\ S = p_1 \times p_2 \times \cdots \times p_s \]

我们可以发现指数\(\alpha\)是没有影响的,我们可以只考虑\(a_i\)的次数为\(1\)\(0\)\(2^s-1\)个因数。这些数可以用\(V_i\)这个\(s\)位二进制数表示,在预处理的时候对这些数加一。询问的时候考虑计算

\[\sum (-1)^{|V_i|}S_i \\ S_i=\prod_{i=0}^{s-1} [V_i]\times p_i \]

这个值就是在\(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;
}
posted @ 2021-05-05 20:25  tianyy  阅读(55)  评论(1)    收藏  举报