模拟测试20190803

日常测试被爆踩,sdfz大佬太NB了好嘛,(比外校低70分身败名裂

今天早上头铁调二分套主席树直接死亡,rp++(这一定是考得还行的主要原因)

开始考试,上来T1数据范围1e12惊心动魄,推了一会发现没有头绪,跳T2

T2上来,WC原题,立马打了个暴力,刚准备码个STL,突然想到vector不能修改(是我太天真),后来想用set,发现set下标不能相减。。。。一度十分MB

然后突然想到,诶我可以用线段树维护啊,码码码,30分钟码完,和暴力拍上就去看T3

主要过程:诶这玩意怎么做啊,最优解怎么求啊,复杂度怎么办啊,算了去看T1(无比真实)

看了看T1数据范围,诶70pts可以直接跑lca啊,码码码,诶怎么建树啊,然后我就码了这个东西

考完看题解我才知道我一度和正解多么接近

最后lca骗了70分,排行榜上往上往下一片AC,我%……&%@@#¥%¥

然后肛T3,发现k==1的40pts可以在O(nsqrt(max(a[i])))复杂度里搞定,码码码,码完还有30分钟,想着多骗点分就码了个dfs,成功多骗了16pts

出成绩后T2re80十分难过,赶紧开大数组然后TLE85,突然不怎么难过了,反正就丢了5pts(事后加fread成功AC)

总分70+80+56=206,rank3还可以吧,主要上次太菜了,这次也算挽回了一些?

T1:斐波那契(fibonacci)

看上去这颗树没有什么规律,但是我们仔细观察编号规则就会发现,fi[i-1]+1~fi[i]的这些数的父亲分别是了1~f[i]-f[i-1],而我们可以发现树的深度最大为59

所以我们对于每个询问可以直接向上标记来求lca,复杂度O(60m)

T2:数颜色

几乎原题这里就不说了,STL,动态开店,主席树都行,复杂度O(nlogn)

T3:分组

很容易发现所谓字典序最小就是从后往前每个块尽量大,现在主要问题是怎么判定能否成立

k=1时,开一个桶维护出现过的值,扫描所有平方数判断就好了

k=2时,同样开一个桶维护出现过的值,但是需要用扩展域并查集维护所有和某个权值加和为平方数的所有值,即将他们在并查集里合并

每次新扫一个点时,判断他和某个出现过的和他加和是平方数的数是否在同一并查集里就好了

还有需要特判相同权值,很容易发现当且仅当有其他和他们加和为平方数的数时不成立

复杂度O(nsqrt(n))(不考虑并查集复杂度)

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int a=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+ch-'0',ch=getchar();
    return a; 
}
int ma=0x3f3f3f3f,v[500010],a[500010],s1[500010],s2[500010],t1,t2,sta[500010],top,en[500010],is[500010],f[500010],hate[500010];
int find(const int x){
    return f[x]=f[x]==x? x:find(f[x]);
}
int main(){
    int n,k,num=0,ans=1,mx=0,x,y;
    n=read();k=read();
    for(int i=1;i<=n;i++) a[i]=read(),mx=max(mx,a[i]);
    mx=sqrt(mx*2.0);
    for(int i=2;i<=512;i++) is[i*i]=1;
    if(k==1){
        for(int i=n;i>=1;i--){
            for(int j=mx;j>=2&&j*j>a[i];j--)
                if(v[j*j-a[i]]==ans){
                    sta[++top]=i;
                    ans++;
                    break;
                }
            v[a[i]]=ans;
        }
        printf("%d\n",ans);
        for(int i=top;i>=1;i--) printf("%d ",sta[i]);
        puts("");
        return 0;
    }
    for(int i=1;i<=131072;i++) f[i]=i;
    sta[0]=n;
    for(int i=n;i>=1;i--){
        for(int j=mx;j>=2&&j*j>a[i];j--)
            if(v[j*j-a[i]]==ans){
                int p=j*j-a[i];
                if(a[i]==p){
                    if(hate[a[i]]){
                        for(int t=i;t<=sta[ans-1];t++) f[a[t]]=a[t],hate[a[t]]=0;
                        sta[ans++]=i;
                        break;
                    }
                    else hate[a[i]]=p;
                }
                else{
                    if((find(a[i])==find(p)&&a[i]!=p)||hate[p]==p){
                        for(int t=i;t<=sta[ans-1];t++) f[a[t]]=a[t],hate[a[t]]=0;
                        sta[ans++]=i;
                        break;
                    }
                    if(hate[a[i]]){
                        x=find(hate[a[i]]),y=find(p);
                        f[x]=y;
                    }
                    else hate[a[i]]=p;
                    if(hate[p]){
                        x=find(a[i]),y=find(hate[p]);
                        f[x]=y;
                    }
                    else hate[p]=a[i];
                }
            }
        v[a[i]]=ans;
    }
    printf("%d\n",ans);
    for(int i=ans-1;i>=1;i--) printf("%d ",sta[i]);
    puts("");
}
View Code

猜你喜欢

转载自www.cnblogs.com/mikufun-hzoi-cpp/p/11295427.html