zoukankan      html  css  js  c++  java
  • [BJOI2016]水晶 做题心得

    [BJOI2016]水晶 做题心得

    这是一个写了我两小时的傻逼题。写这个题浪费了一堆时间后,我才意识到我码力又不行了。于是整理起了实现技巧,开始练码力。

    思路

    不难。首先把 ((x,y,z)) 变成 ((x-z,y-z))。因为发现 ((x,y,z)) 同时减去某个数表示的位置不变,同时减去 (z),把坐标只用 (x,y) 来描述。

    发现是关于点权的,先把每个点拆成入点和出点,连一条边表示它的点权。假设入,出点分别是 (a_i,a_o)

    然后枚举一下每个三角形,每个直线,假设是 ((a,b,c))

    那么这样连边:

    (S xrightarrow[INF]{} a_i xrightarrow[val_a]{} a_o xrightarrow[INF]{} b_ixrightarrow[val_b]{} b_oxrightarrow[INF]{} c_ixrightarrow[val_c]{}c_oxrightarrow[INF]{} T)

    实现问题&改进

    1. 发现这样连边会连出环来。解法是,考虑按 ((x+y)\%3) 分类,强行钦定某个顺序。这样就不会产生环了。

    2. 分开考虑三角形和直线太麻烦了,而且非常容易写错。我因此写错了 (114514) 次。事实上可以一块考虑,对于每个((x+y)\%3=0) 的,考虑它的“六周” (“四周”这个词在本题中的引申,注意到相邻的有六个点),不能有相邻的 (\%3=1)(\%3=2) 的。
      然后可以这样建,(\%3=1) 的接 (S)(\%3=2) 的接 (T)(\%3=0) 的,向周围的 (\%3=2) 的连一条,然后周围 (\%3=1) 的向它来连一条,就可以完成建图了

      这样结构更加清楚,简单,不容易写挂

      (是参考了一篇题解中的实现

    代码

    #include <bits/stdc++.h>
    using namespace std;
    namespace Flandre_Scarlet
    {
    	#define N   400005
    	#define INF 600000000
    	#define F(i,l,r) for(int i=l;i<=r;++i)
    	#define D(i,r,l) for(int i=r;i>=l;--i)
    	#define Fs(i,l,r,c) for(int i=l;i<=r;c)
    	#define Ds(i,r,l,c) for(int i=r;i>=l;c)
    	#define MEM(x,a) memset(x,a,sizeof(x))
    	#define Tra(i,u) for(int i=G.st(u),v=G.to(i);~i;i=G.nx(i),v=G.to(i))
    	#define p_b push_back
    	#define sz(a) ((int)a.size())
    	#define all(a) a.begin(),a.end()
    	#define iter(a,p) (a.begin()+p)
    	int I() {char c=getchar(); int x=0; int f=1; while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar(); while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return ((f==1)?x:-x);}
    	template <typename T> void Rd(T& arg){arg=I();}
    	template <typename T,typename...Types> void Rd(T& arg,Types&...args){arg=I(); Rd(args...);}
    	void RA(int *p,int n) {F(i,1,n) *p=I(),++p;}
    	int n;
    	int x[N],y[N],c[N];
    	map<pair<int,int>,int> rec,rid;
    	#define rc(x,y) rec[make_pair(x,y)]
    	#define ri(x,y) rid[make_pair(x,y)] 
        void Input()
        {
        	n=I();
        	F(i,1,n)
        	{
        		int z; Rd(x[i],y[i],z,c[i]); c[i]*=10;
        		x[i]-=z; y[i]-=z;
        		if ((x[i]+y[i])%3==0) c[i]+=c[i]/10;
    
        		rc(x[i],y[i])+=c[i];
        	}
        }
        class NetworkFlow
        {
        public:
            int S,T,n;
            struct edge
            {
                int v,c,nx;
            }pool_e[4000000+2]; edge *e;
            int pool_h[N+2]; int *head;
            int pool_c[N+2]; int *cur;
            int ecnt=-1;
            void clear()
            {
                ecnt=-1;
                MEM(pool_e,-1); e=pool_e+2;
                MEM(pool_h,-1); head=pool_h+2;
                MEM(pool_c,-1); cur=pool_c+2;
                // 允许 [-1]的访问
            }
            void add(int u,int v,int c)
            {
                e[++ecnt]={v,c,head[u]}; head[u]=ecnt;
            }
            void addflow(int u,int v,int c)
            {
            	// printf("flow %d %d %d
    ",u,v,c);
                add(u,v,c); 
                add(v,u,0);
            }
            int& st(int u) {return head[u];}
            int& cu(int u) {return cur[u];}
            int& to(int i) {return e[i].v;}
            int& cap(int i) {return e[i].c;}
            int& nx(int i) {return e[i].nx;}
            #define Trah(i,u) for(int i=st(u),v=to(i);~i;i=nx(i),v=to(i))
            #define Trac(i,u) for(int &i=cu(u),v=to(i);~i;i=nx(i),v=to(i))
    
            queue<int> Q;
            int dep[N];
            bool BFS()
            {
                while(!Q.empty()) Q.pop(); F(i,1,n) dep[i]=INF;
                dep[S]=1; cur[S]=head[S]; Q.push(S);
                while(!Q.empty())
                {
                    int u=Q.front(); Q.pop();
                    if (u==T) return true;
                    Trah(i,u) if (cap(i) and dep[v]==INF)
                    {
                        dep[v]=dep[u]+1;
                        cur[v]=head[v];
                        Q.push(v);
                    }
                }
                return false;
            }
            int  DFS(int u,int flow)
            {
                if (u==T) return flow;
                int ans=0;
                Trac(i,u) 
                {
                    if (!flow) break;
                    if (cap(i) and dep[v]==dep[u]+1)
                    {
                        int f=DFS(v,min(flow,cap(i)));
                        if (!f)
                        {
                            dep[v]=INF;
                        }
                        else
                        {
                            cap(i)-=f; cap(i^1)+=f;
                            flow-=f; ans+=f;
                        }
                    }
                }
                return ans;
            }
            int  Dinic()
            {
                int ans=0;
                while(BFS()) ans+=DFS(S,INF);
                return ans;
            }
    
            NetworkFlow() {clear();}
            NetworkFlow(int s,int t,int nn) {clear(); S=s; T=t; n=nn;}
        }Nt;
        int tot=0,S=1,T=2;
        int in[N],out[N];
        void Sakuya()
        {
        	int point=0;
        	tot=2;
        	F(i,1,n) c[i]=x[i]=y[i]=0;
        	for(auto p:rec)
        	{
        		int i=p.first.first,j=p.first.second;
        		++point;
    
        		x[point]=i;
        		y[point]=j;
        		c[point]=rc(i,j);
        		ri(i,j)=point;
        		in[point]=++tot;
        		out[point]=++tot;
        	}
        	Nt=NetworkFlow(S,T,tot);
        	F(i,1,point)
        	{
        		int t=((x[i]+y[i])%3+3)%3;
        		if (t==1) Nt.addflow(S,in[i],INF);
        		if (t==2) Nt.addflow(out[i],T,INF);
        		else
        		{
        			int nx;
        			nx=ri(x[i]-1,y[i]-1); if (nx) Nt.addflow(out[nx],in[i],INF);
        			nx=ri(x[i]+1,y[i]); if (nx) Nt.addflow(out[nx],in[i],INF);
        			nx=ri(x[i],y[i]+1); if (nx) Nt.addflow(out[nx],in[i],INF);
    
        			nx=ri(x[i]+1,y[i]+1); if (nx) Nt.addflow(out[i],in[nx],INF);
        			nx=ri(x[i]-1,y[i]); if (nx) Nt.addflow(out[i],in[nx],INF);
        			nx=ri(x[i],y[i]-1); if (nx) Nt.addflow(out[i],in[nx],INF);
        		}
        		Nt.addflow(in[i],out[i],c[i]);
        	}
    
        	int sum=0; F(i,1,point) sum+=c[i];
        	int ans=sum-Nt.Dinic();
        	printf("%d.%d
    ",ans/10,ans%10);
        }
        void IsMyWife()
        {
            Input();
            Sakuya();
        }
    }
    #undef int //long long
    int main()
    {
        Flandre_Scarlet::IsMyWife();
        getchar();
        return 0;
    }
    

    后记:两种实现的比较

    1. 原实现长达 (220) 行,改进实现只有 (182) 行。

    2. 原实现(提到过)WA了 (114514) 次,最高拿了 (35),到现在还不知道问题在哪,没调出来,也不想调了,nmsl (暴躁)

      相比较改进实现一遍就A了。

    所以说,码力的提升还是很重要的。

  • 相关阅读:
    绘图1——图形标记
    polyfit实例1
    polyfit函数-帮助文档
    C# 中泛型与非泛型?(摘)
    C# 数组和集合(摘)
    C#中字符与字符串(转)
    C# 表达式与运算符(转)
    C#中的变量和常量(转)
    C#变量的声明和初始化(转)
    变量的声明、定义、初始化(转)
  • 原文地址:https://www.cnblogs.com/LightningUZ/p/14198325.html
Copyright © 2011-2022 走看看