• NOIP 模拟 9 分组


    题解

    这道题我们发现可以根据 (k=1)(k=2) 的情况分别讨论

    (k=1) 时,我们发现要保证字典序,那么我们从后往前扫,扫的时候判断一下当前数是否会和上一段的冲突。

    复杂度瓶颈就在于如何判断。我们发现 (a_ileq 2^{17}) 所以 (j*j=a_i+a_k)(j) 最大为 (2^9),所以我们可以枚举 (j),记录一个数组,判断一下 (j*j-a_i) 是否出现过

    最后若分出新的一段,记得要把前一段的清空。

    (k=2) 时,我们可以把每个数拆成两个点,分别为 (x_1)(x_2)(y_1)(y_2),让后将冲突的数连起来,发现如果其符合二分图,那么就可以分为一组。

    对于判断二分图,我们可以用并查集替代。(思想

    对于每个数,我们给他开一个敌人域,每次若发现冲突,但可以分成两个团体解决,那么我们将两个树的敌人域向与其发生冲突的数合并

    判断时就是判断 (x_1) 是否和 (y_1) 在一个集合里。

    Code:
    #include<bits/stdc++.h>
    #define ri register signed
    #define p(i) ++i
    using namespace std;
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
        inline int read() {
            ri x=0,f=1;char ch=gc();
            while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
            while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            return x*f;
        }
    }
    using IO::read;
    namespace nanfeng{
        #define cmax(x,y) ((x)>(y)?(x):(y))
        #define cmin(x,y) ((x)>(y)?(y):(x))
        #define FI FILE *IN
        #define FO FILE *OUT
        static const int N=(1<<17)+7;
        int a[N],vis[N],st[N],fa[N<<1],fg[N<<1],n,k,tot=1,mx;
        int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
        inline int main() {
            // FI=freopen("nanfeng.in","r",stdin);
            // FO=freopen("nanfeng.out","w",stdout);
            n=read(),k=read();
            for (ri i(1);i<=n;p(i)) a[i]=read(),mx=cmax(mx,a[i]);
            vis[a[n]]=1;st[1]=n;
            if (k==1) {
                for (ri i(n-1);i;--i) {
                    for (ri j(ceil(sqrt(a[i])));j*j-a[i]<=mx;p(j)) {
                        if (j*j>=a[i]&&vis[j*j-a[i]]) {
                            st[p(tot)]=i;
                            for (ri k(i+1);k<=st[tot-1];p(k)) vis[a[k]]=0;
                            break;
                        }
                    }
                    vis[a[i]]=1;
                }
            } else {
                for (ri i(1);i<=mx;p(i)) fa[i]=i,fa[i+mx]=i+mx;
                for (ri i(1);i*i<=(mx<<1);p(i)) fg[i*i]=1;
                for (ri i(n-1);i;--i) {
                    ri fl=0;
                    if (vis[a[i]]) {
                        if (fg[a[i]<<1]) {
                            if (vis[a[i]]==2||fa[a[i]+mx]!=a[i]+mx) fl=1;
                        }
                    } else {
                        for (ri j(ceil(sqrt(a[i])));j*j-a[i]<=mx;p(j)) {
                            if (vis[j*j-a[i]]) {
                                if (fg[(j*j-a[i])<<1]&&vis[j*j-a[i]]==2) {fl=1;break;}
                                int x1=find(a[i]),x2=find(a[i]+mx),y1=find(j*j-a[i]),y2=find(j*j-a[i]+mx);
                                if (x1==y1) {fl=1;break;}
                                fa[y2]=x1;fa[x2]=y1;
                            }
                        }
                    }
                    if (fl) {
                        for (ri j(i);j<=st[tot];p(j)) fa[a[j]]=a[j],fa[a[j]+mx]=a[j]+mx,vis[a[j]]=0;
                        st[p(tot)]=i;
                    }
                    p(vis[a[i]]);
                }
            }
            printf("%d
    ",tot);
            for (ri i(tot);i>1;--i) printf("%d ",st[i]);
            puts("");
            return 0;
        }
    }
    int main() {return nanfeng::main();}
    
  • 相关阅读:
    线程带参数操作
    静态页面不识别include
    当网站遭遇DDOS攻击的解决方案及展望
    带进度条上传控件
    用js实现了表格数据管理的以下几个功能:
    怎么面试一个人
    map的使用
    在Axapta中实现trim函数
    Axapta财务过账分析(一)
    在Axapta中实现split函数
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/14919163.html
Copyright © 2020-2023  润新知