zoukankan      html  css  js  c++  java
  • [NOIP2018模拟10.15]比赛报告

    闲扯

    昨晚又颓到好晚,Yali的降智光环感觉持续至今...

    题面好评 T1T3都玩过 逃)

    T1没看多久就开始写二分+并查集 然后T3看着眼熟想了一个多小时...结果啥都没想出来

    赶紧看T2发现还是没什么思路,码个暴力回来看T1,发现了两个致命又SB的错误,倒数15分钟前终于改回来,刺激

    结果80+35+0 T1还是挂分了,检查时发现还是一个思博错误,没有判上下相连与左右相连情况,感谢出题人良心数据

    T2调了好久结果爆栈RE,不想改了。T3听完晚上的讲评后才茅塞顿开,太菜了

    T1 刺客信条 AC

    分析

    我的做法很naiive,直接距离,将每个人看成圆心画一个二分距离的圆,两个圆有交就连在一起,最后判断Ezio能不能过去.

    这里的判读大佬们都是将4面墙看成4个点处理,我最SB,每个点开四个bool变量记录,合并时暴力合并bool值

    std求了个最小生成树,比较神奇

    然后加了一些优化,预处理点对距离,特判之类的一开始跑了个rank4

    代码

    /*
      code by RyeCatcher
    */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cctype>
    #include <utility>
    #include <cmath>
    #include <queue>
    #include <vector>
    #include <ext/pb_ds/hash_policy.hpp>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <iostream>
    #define DEBUG freopen("dat.in","r",stdin);freopen("wa.out","w",stdout);
    #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
    #define ri register int
    #define ll long long
    #define ull unsigned long long
    #define SIZE 1<<22
    using std::sqrt;
    using std::min;
    using std::max;
    using std::priority_queue;
    using std::queue;
    using std::vector;
    using std::pair;
    using namespace __gnu_pbds;
    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    #define gc getchar
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x*10)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=3005;
    const int inf=0x7fffffff;
    const long double eps=1e-7;
    struct Pt{
        long double x,y;
    }pt[maxn];
    long double X,Y;
    int fa[maxn];
    struct Flag{
        bool f1,f2,f3,f4;
        inline void clear(){f1=f2=f3=f4=0;}
    }ff[maxn];
    inline void merge(int x,int y){
        if(ff[x].f1|ff[y].f1)ff[x].f1=ff[y].f1=1;
        if(ff[x].f2|ff[y].f2)ff[x].f2=ff[y].f2=1;
        if(ff[x].f3|ff[y].f3)ff[x].f3=ff[y].f3=1;
        if(ff[x].f4|ff[y].f4)ff[x].f4=ff[y].f4=1;
        return ;
    }
    int get(int x){
        merge(x,fa[x]);
        if(fa[x]!=x){
            fa[x]=get(fa[x]);
        }
        return fa[x];
    }
    bool vis[maxn];
    long double fafa[maxn][maxn];
    int n;
    bool check(long double Dis){
        for(ri i=1;i<=n;i++){
            vis[i]=0;
            fa[i]=i;
    		ff[i].clear();
        }
        long double x,y;
        for(ri i=1;i<=n;i++){
        	int cnt=0;
            x=pt[i].x,y=pt[i].y;
            if(Dis-x>1e-11)ff[i].f1=1,cnt++;
            if(Dis-y>1e-11)ff[i].f2=1,cnt++;
            if(Dis-(X-x)>1e-11)ff[i].f3=1,cnt++;
            if(Dis-(Y-y)>1e-11)ff[i].f4=1,cnt++;
            //if(cnt>=2)return 1;
            if(ff[i].f1&&ff[i].f2)return 1;
            if(ff[i].f3&&ff[i].f4)return 1;
            
        }
        int fx,fy;
        for(ri i=1;i<=n;i++){
            x=pt[i].x,y=pt[i].y;
            for(ri j=i+1;j<=n;j++){
                long double p=fafa[i][j];
                if(Dis*2-p>1e-11){
                    fx=get(i),fy=get(j);
                    fa[fx]=fy;
                    merge(fx,fy);
                }
            }
        }
        for(ri i=1;i<=n;i++){
            fx=get(i);
            if(vis[fx])continue;
            vis[fx]=1;
            int tmp=ff[fx].f1+ff[fx].f2+ff[fx].f3+ff[fx].f4;
            if(ff[fx].f1&&ff[fx].f2)return 1;
            if(ff[fx].f3&&ff[fx].f4)return 1;
            if(ff[fx].f2&&ff[fx].f4)return 1;
            if(ff[fx].f1&&ff[fx].f3)return 1;
        }
        return 0;
    }
    int main(){
    	long double x,y;
    	//freopen("AC.in","r",stdin);
    	//freopen("AC.out","w",stdout);
        read(X),read(Y),read(n);
        for(ri i=1;i<=n;i++){
            read(pt[i].x),read(pt[i].y);
        }
        for(ri i=1;i<=n;i++){
            x=pt[i].x,y=pt[i].y;
            for(ri j=i+1;j<=n;j++){
                fafa[i][j]=sqrtl((x-pt[j].x)*(x-pt[j].x)+(y-pt[j].y)*(y-pt[j].y));
            }
        }
        long double mid,L=0,R=sqrtl(X*X+Y*Y+233);
        while(R-L>eps){
            mid=(L+R)/2;
            if(check(mid))R=mid;
            else L=mid;
            //printf("%.4lf %.4lf
    ",L,R);
        }
        printf("%.2Lf
    ",R);
        return 0;
    }
    
    

    T2 黑暗之魂 darksoul

    分析

    先不考虑自环和重边,最终的图像肯定是一个环,环上若干点,点可能向外扩展成一棵树

    假如最终答案在一颗树中,我们就要求出树上相距最远的两点,用树形DP即可,

    (g[x])表示向下在以x为根的子树中最远能扩展到哪里,(o[x])表示次远值

    g[x]=max(g[x],g[v]+dis(x,v)),o[x]就不赘述了

    然后以x为LCA的两点最远值f[x]=g[x]+o[x],然后(max_{x in T}(f[x]))就是树T的贡献

    但是如果答案的路径经过了环上的边呢,对于环上路径((x,y)). (x,y都是环上的点)

    它的贡献为(g[x]+g[y]+dis(x,y))

    (g)值我们是已经求出来的,但是(dis)怎么求?我们化环为链,钦定起点(st),用前缀和数组(pre[x])表示(dis(st,x))

    那么(dis(x,y))就是(pre[x]-pre[y])(设(x)(y)之后),注意我们要倍长这条链

    这样贡献就变成了(g[x]+pre[x]+g[y]-pre[y])

    然而需要注意的是如果(pre[x]-pre[y])大于环周长的一半是不合法的,为啥?因为他总是选择最短路走,既然这段大于周长一半,反过来走肯定更短

    暴力的做法就是N方环上每一对点枚举一遍,考虑高级一点的做法,发现化环为链后处理的(pre)数组是单调递增的,

    于是维护一个(g[y]-pre[y])值递减的滑动窗口(因为当前点为(x),(g[x]+pre[x])是固定的),一旦队头(p)到当前点距离,即(pre[x]-pre[p])大于两倍周长就弹出队头

    然后大佬们都是用拓扑排序搞,我只会naiive的深搜,然后交上去最后两个点爆栈了

    同时还发现我没有考虑答案是在一棵树中的情况,只能说这数据水了...

    代码

    /*
      code by RyeCatcher
    */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cctype>
    #include <utility>
    #include <queue>
    #include <vector>
    #include <ext/pb_ds/hash_policy.hpp>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <iostream>
    #define DEBUG freopen("dat.in","r",stdin);freopen("wa.out","w",stdout);
    #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
    #define ri register int
    #define ll long long
    #define ull unsigned long long
    #define SIZE 1<<22
    using std::min;
    using std::max;
    using std::priority_queue;
    using std::deque;
    using std::vector;
    using std::pair;
    using namespace __gnu_pbds;
    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=2000005;
    const int inf=0x7fffffff;
    struct Edge{
    	int ne,to;
    	ll dis;
    }edge[maxn<<1];
    int h[maxn];ll num_edge=1;
    inline void add_edge(int f,int to,ll c){
    	edge[++num_edge].ne=h[f];
    	edge[num_edge].to=to;
    	edge[num_edge].dis=c;
    	h[f]=num_edge;
    }
    int n;
    int fa[maxn],dep[maxn];
    bool vis[maxn],flag_1;
    int fo1,fo2;
    void pre_dfs(int now,int fa){
        int v;
        vis[now]=1;
        for(ri i=h[now];i;i=edge[i].ne){
            v=edge[i].to;
            if(v==fa)continue;
            if(vis[v]&&dep[v]==dep[now]+1){
            	//puts("11");
    			for(ri k=h[now];k;k=edge[k].ne){
    				//printf("%d
    ",edge[k].to);
    				if(edge[k].to==v){
    					if(!fo1)fo1=k;
    					else fo2=k;
    				}
    			}
    			flag_1=1;return ;
    		}
    		else if(vis[v])continue;
            dep[v]=dep[now]+1;
            pre_dfs(v,now);
        }
        return;
    }
    namespace Tree{
        ll Tmp=-1,ans=-1;
        int rt=1;
        void dfs_1(int now,int fa,ll dis){
            int v;
            if(Tmp<dis){
                rt=now,Tmp=dis;
            }
            for(ri i=h[now];i;i=edge[i].ne){
                v=edge[i].to;
                if(i==fo1||i==fo2)continue;
                if(v==fa||v==now)continue;
                dfs_1(v,now,dis+edge[i].dis);
            }
            return ;
        }
        void dfs_2(int now,int fa,ll dis){
            int v;
            ans=max(ans,dis);
            for(ri i=h[now];i;i=edge[i].ne){
                v=edge[i].to;
                if(i==fo1||i==fo2)continue;
                if(v==fa||v==now)continue;
                dfs_2(v,now,dis+edge[i].dis);
            }
            return ;
        }
        void main(){
        	if(edge[fo1].dis<edge[fo2].dis){
        		fo1=fo2^1;
    		}
    		else{
    			fo2=fo1^1;
    		}
            dfs_1(1,0,0);
            Tmp=-1;
            dfs_2(rt,0,0);
            printf("%lld
    ",ans+1);
            return ;
        }
    }
    int sta[maxn],cnt=0,st,ed,len=0;
    bool on_cyc[maxn];
    void find_cyc(int now){
    	int v;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(v==fa[now])continue;
    		if(dep[v]&&dep[v]<dep[now]){
    			st=now,ed=v;
    			int x=now;
    			while(x!=v)len++,on_cyc[x]=1,sta[++cnt]=x,x=fa[x];
    			len++,on_cyc[v]=1,sta[++cnt]=v;
    			continue;
    		}
    		else if(dep[v])continue;
    		fa[v]=now;
    		dep[v]=dep[now]+1;
    		find_cyc(v);
    	}
    	return ;
    }
    int rt;
    ll dm[maxn];
    ll tmp=-1,cc=0;
    ll dp[maxn];
    void dfs_1(int now,int fa){
    	int v;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(on_cyc[v]||v==fa)continue;
    		dfs_1(v,now);
    		dp[now]=max(dp[now],dp[v]+edge[i].dis);
    	}
    	return ;
    }
    ll pre[maxn];//dist from st
    int ff[maxn],ne[maxn],tot=0;
    void dfs_on_cyc(int now,int fa){
    	int v;
    	if(tot==len*2-1)return ;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(v!=ne[now])continue;
    		pre[tot+1]=pre[tot]+edge[i].dis;
    		ff[++tot]=v;
    		if(tot==len+1)cc=pre[tot];
    		dfs_on_cyc(v,now);
    	}
    	return ;
    }
    deque <int> q;
    ll arr[maxn];
    int main(){	
    	bool flag=0;
    	int x,y;ll z;
    	FO(darksoul);
    	//freopen("darksoul19.in","r",stdin);
    	read(n);
    	//puts("sss");
    	//system("PAUSE");
    	for(ri i=1;i<=n;i++){
    		read(x),read(y),read(z);
    		add_edge(x,y,z);
    		add_edge(y,x,z);
    		if(x==y)flag=1;
    	}
    	dep[1]=1;
    	pre_dfs(1,0);
    	if(flag||flag_1){
    		//puts("ss");
    		Tree::main();return 0;
    	}
    	//memset(vis,0,sizeof(vis));
    	memset(dep,0,sizeof(dep));
    	fa[1]=0,dep[1]=1;
    	find_cyc(1);
    	for(ri i=1;i<=cnt;i++){
    		rt=sta[i];
    		if(i!=cnt)ne[sta[i]]=sta[i+1];
    		else ne[sta[i]]=sta[1];
    		tmp=-1;
    		dfs_1(rt,0);
    		dm[sta[i]]=dp[rt];
    	}
    	tot=1,ff[1]=sta[1];
    	dfs_on_cyc(st,0);
    	for(ri i=1;i<=len*2-1;i++){		
    		arr[i]=dm[ff[i]]-pre[i];
    	}
    	ll ans=-1;
    	for(ri k=1;k<=len*2-1;k++){				
    		if(q.empty())q.push_back(k);
    		else{	
    			while(q.size()&&pre[k]-pre[q.front()]>cc/2)q.pop_front();		
    			ans=max(ans,dm[ff[k]]+pre[k]+arr[q.front()]);
    			while(q.size()&&arr[q.back()]<=arr[k])q.pop_back();
    			q.push_back(k);
    		}
    	}
    	printf("%lld
    ",ans+1);
    	return 0;
    }
    
    

    T3 传送门 portal

    分析

    巧妙的树形DP

    假设当前我们正在(x)点,(y)(x)的一个儿子,(f[x])表示以(x)为根的子树的最优答案,

    ialsk4.png

    那么我们考虑假如传送门在(y),那么(y)的贡献就是(f[y]+c*2),因为(x,y)还得靠你自己走

    假如一个传送门在(x),那么(y)的贡献为(sum_e(y) imes 2-g(y)+c),(sum_e(y))表示(y)的子树中边权之和,(g(y)表示)(y)的子树中的最长链长度.

    这时候有人会问一个问题,你这样为什么不每次走到底再传送到x然后再经过(c),但是这样的话要经过多次(c),为什么不干脆将传送门设在(y),这样的贡献肯定不会比你那样走更多,所以我们这时候要选择最长链跳,其余的都靠步行的方式计算贡献

    综上(f[x]= sum min(f[y]+c imes 2,sum_e(y) imes 2-g(y)+c))

    由于我们能够安排儿子的(dfs)顺序,可知儿子之间是不会互相影响的

    代码

    /*
      code by RyeCatcher
    */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cctype>
    #include <utility>
    #include <queue>
    #include <vector>
    #include <ext/pb_ds/hash_policy.hpp>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <iostream>
    #define DEBUG freopen("dat.in","r",stdin);freopen("wa.out","w",stdout);
    #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
    #define ri register int
    #define ll long long
    #define ull unsigned long long
    #define SIZE 1<<22
    using std::min;
    using std::max;
    using std::priority_queue;
    using std::queue;
    using std::vector;
    using std::pair;
    using namespace __gnu_pbds;
    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    #define gc getchar
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=1000005;
    const int inf=0x7fffffff;
    int n;
    struct Edge{
    	int ne,to;
    	ll dis;
    }edge[maxn<<1];
    int h[maxn],num_edge=1;
    inline void add_edge(int f,int to,ll c){
    	edge[++num_edge].ne=h[f];
    	edge[num_edge].to=to;
    	edge[num_edge].dis=c;
    	h[f]=num_edge;
    }
    ll g[maxn],s[maxn],f[maxn];
    void dfs(int now,int fa){
    	int v;ll c;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(v==fa)continue;
    		dfs(v,now);
    		c=edge[i].dis;
    		s[now]=s[now]+s[v]+c;
    		g[now]=max(g[now],g[v]+c);
    		f[now]+=min(s[v]*2-g[v]+c,f[v]+c*2);
    	}
    	return ;
    }
    int main(){
    	int x,y,z;
    	FO(portal);
    	read(n);
    	for(ri i=1;i<n;i++){
    		read(x),read(y),read(z);
    		add_edge(x,y,z);
    		add_edge(y,x,z);
    	}
    	dfs(1,0);
    	printf("%lld
    ",f[1]);
    	return 0;
    }
    
    
    
  • 相关阅读:
    浅谈分布式 ID 的实践与应用
    Mobile DevOps 之 Proxmox 实现节流提效
    AI驱动的超分辨技术落地实践
    element ui 的 element-tree文字显示不全的问题
    Skype for business Server 2019 私有化部署
    VSCode+XAMAPP的PHP断点调试环境搭建XDebug
    Office的密码破和原理说明Excel,ppt,word
    Exchange2016 归档功能设置保留策略就地存档Archive
    基于windows server216自带的备份服务windows server backup
    C# 操作xml基础整理【转】
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9795397.html
Copyright © 2011-2022 走看看