noip模拟9

宜:重构代码

T1

70分做法就是把1e6以内的直接父亲都暴力处理出来,询问时在线递归处理即可。

100分做法,发现每一层的最后一个数都是斐波那契数的一个值,并且一个数的父亲是这个数减去它的上一层的斐波那契数。求两个数祖先时一直递归往上跳,直到跳到二者相同时返回。

Code

#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
namespace EMT{
    typedef long long ll;
    inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
    #define pf printf
    #define F(i,a,b) for(register int i=a;i<=b;i++)
    #define D(i,a,b) for(register int i=a;i>=b;i--)
    inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
    ll f[65]={0,1,2};int m;
    ll max(ll a,ll b){return a>b?a:b;}
    int getdp(ll x){
        int l=1,r=60,ans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(f[mid]<x)l=mid+1,ans=mid;
            else r=mid-1;
        }return ans;
    }
    inline ll getfa(ll x,ll y,int dep){
        if(x==y)return x;
        else if(x>y)return getfa(x-f[dep],y,getdp(max(x-f[dep],y)));
        else return getfa(x,y-f[dep],getdp(max(x,y-f[dep])));
    }
    inline short main(){
        F(i,3,60)f[i]=f[i-1]+f[i-2];
        m=read();
        F(i,1,m){
            ll x=read(),y=read(),z=getdp(max(x,y));
            pi(getfa(x,y,z));pn();
        }
        return 0;
    }
}
int main(){return EMT::main();}

T2

有一个点卡了我好久啊。。。

不过我是不会放弃骗分分块的!

加了个小优化,结果一直T的点反而变成最快的点了...

Code

#include<bits/stdc++.h>
namespace EMT{
    inline int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x;}
    inline void write(int x){
        static int sta[35];int top=0;
        do{sta[++top]=x-(x/10)*10,x/=10;}while(x);
        while(top) putchar(sta[top--]+'0');
        putchar('\n');
    }
    inline void swap(int &a,int &b){int x=a;a=b,b=x;}
    const int N=3e5+10;
    short sum[400][N];
    int size,n,m,a[N],pos[N],L,R,sp,x,c,ans;
    inline short main(){
        n=read();m=read();
        size=pow(n,5.0/8.0);
        for(int i=1;i<=n;i++)a[i]=read(),pos[i]=(i-1)/size+1,++sum[pos[i]][a[i]];
        while(m--){
            sp=read();
            if(sp==1){
                L=read(),R=read(),c=read(),ans=0;
                if(pos[L]==pos[R]){
                    if(R-L+1<=size/2)for(int i=L;i<=R;i++)ans+=(a[i]==c);
                    else{
                        ans=sum[pos[L]][c];
                        for(int i=size*(pos[L]-1)+1;i<=L-1;i++)ans-=(a[i]==c);
                        for(int i=R+1;i<=size*pos[L];i++)ans-=(a[i]==c);
                    }
                    write(ans);
                }else{
                    if(pos[L]*size-L+1<=size/2)for(int i=L;i<=pos[L]*size;i++)ans+=(a[i]==c);
                    else{
                        ans=sum[pos[L]][c];
                        for(int i=size*(pos[L]-1)+1;i<=L-1;i++)ans-=(a[i]==c);
                    }
                    for(int i=pos[L]+1;i<=pos[R]-1;i++)ans+=sum[i][c];
                    if(R-(pos[R]-1)*size<=size)for(int i=size*(pos[R]-1)+1;i<=R;i++)ans+=(a[i]==c);
                    else{
                        ans+=sum[pos[R]][c];
                        for(int i=R+1;i<=size*pos[R];i++)ans-=(a[i]==c);
                    }
                    write(ans);
                }
            }else{
                x=read();
                if(pos[x]==pos[x+1])swap(a[x],a[x+1]);
                else{
                    --sum[pos[x]][a[x]];++sum[pos[x]][a[x+1]];
                    --sum[pos[x+1]][a[x+1]];++sum[pos[x+1]][a[x]];
                    swap(a[x],a[x+1]);
                }
            }
        }
        return 0;
    }
}
int main(){return EMT::main();}

T3

不知道为什么一直92...重构代码后才过掉了。

倒序枚举是考场上想到了,不过1-512没想到,只想到了\(O(n^2)\)

40分:
枚举查看是否有冲突的即可。

100分:
使用并查集,特判一个数的二倍是不是完全平方数。

Code

#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
int n,k;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
namespace EMT{
	bool v[300000];int a[300000],ans[300000],cnt;
	inline bool is(int x){int y=sqrt(x);return y*y==x;}
	inline bool check(int x,int l,int r){
		if(r-l+1>=512){F(i,1,512)if(v[i*i-x])return 0;}
		else F(i,l,r)if(is(a[i]+x))return 0;
		return 1;
	}
	inline void clean(int l,int r){
		F(i,l,r)v[a[i]]=0;
	}
	inline short main(){
		D(i,n,1)a[i]=read();
		int key=1;v[a[1]]=1;
		F(i,2,n)if(!check(a[i],key,i-1))clean(key,i-1),key=i,v[a[i]]=1,ans[++cnt]=n-i+1;else v[a[i]]=1;
		pi(cnt+1);pn();D(i,cnt,1)pi(ans[i]);
		return 0;
	}
}
namespace emt{
	inline int max(int a,int b){return a>b?a:b;}
	inline int min(int a,int b){return a<b?a:b;}
	const int N=1.5e5;
	int a[500000],ans[500000],fa[500000],maxn,vis[500000],co,cnt;
	inline int find(int x){return (x==fa[x])?x:fa[x]=find(fa[x]);}
	inline bool is(int x){int y=sqrt(x);return y*y==x;}
	inline void clean(int l,int r){F(o,l,r)vis[a[o]]=0,fa[a[o]]=a[o],fa[a[o]+N]=a[o]+N;}
	inline short main(){
		int key=n;bool fl;
		F(i,1,n)a[i]=read(),maxn=max(maxn,a[i]);
		F(i,1,maxn)fa[i]=i,fa[i+N]=i+N;
		D(i,n,1){
			fl=0;
			if(vis[a[i]]){
				if(is(a[i]*2)){
					F(j,1,512){
						if(vis[a[i]]==2||fa[a[i]+N]!=a[i]+N){
							fl=1;break;
						}
						if(j*j<a[i])continue;
						if(j*j>a[i]+maxn)break;
						if(vis[j*j-a[i]]&&j*j!=a[i]*2){
							fl=1;break;
						}
					}
					if(fl){
						ans[++cnt]=i;
						F(j,i,key){
							fa[a[j]]=a[j];fa[a[j]+N]=a[j]+N;
							vis[a[j]]=0;
						}
						key=i;
					}
				}
			}else{
				F(j,1,512){
					if(j*j<a[i])continue;
					if(j*j>a[i]+maxn)break;
					if(vis[j*j-a[i]]){
						if(vis[j*j-a[i]]==2&&is((j*j-a[i])*2)){
							fl=1;
							break;
						}
						int x1=find(a[i]),x2=find(a[i]+N),y1=find(j*j-a[i]),y2=find(j*j-a[i]+N);
						if(x1==y1){
							fl=1;
							break;
						}
						fa[y2]=x1;
						fa[x2]=y1;
					}
				}
				if(fl){
					ans[++cnt]=i;
					F(j,i,key){
						fa[a[j]]=a[j];fa[a[j]+N]=a[j]+N;
						vis[a[j]]=0;
					}
					key=i;
				}
			}
			vis[a[i]]++;
		}
		pi(cnt+1);pn();
		D(i,cnt,1)pi(ans[i]);
		return 0;
	}
}
int main(){
n=read();k=read();
if(k==1)return EMT::main();else return emt::main();}
posted @ 2021-06-23 11:47  letitdown  阅读(46)  评论(0编辑  收藏  举报