• 2020/9/20 NOIP模拟赛


    Preface

    这场的B和C都挺不错的,最后花了2.5h Rush B还好搞出来了

    但是A被SB题面和自己坑了,直接GG

    由于没有题解因此C的做法是陈指导的,但是要讨论好多细节就口胡了


    序列

    显然把输入的数看做点然后前面的向后面连有向边,每次能取的点就是入度为(0)的点

    因此做一个用堆维护最小标号的拓扑排序即可,复杂度(O(nlog n))

    #include<cstdio>
    #include<queue>
    #include<cctype>
    #include<iostream>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T> 
    using namespace std;
    const int N=1000005;
    class FileInputOutput
    {
    	private:
    		static const int S=1<<21;
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
    		char Fin[S],*A,*B;
    	public:
    		Tp inline void read(T& x)
    		{
    			x=0; char ch; while (!isdigit(ch=tc()));
    			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
    		}
    		#undef tc
    }F;
    struct edge
    {
    	int to,nxt;
    }e[N]; int n,k,x,head[N],cnt,deg[N],lst,mx; bool vis[N];
    priority_queue < int,vector<int>,greater<int> > q;
    inline void addedge(CI x,CI y)
    {
    	e[++cnt]=(edge){y,head[x]}; head[x]=cnt; ++deg[y];
    }
    int main()
    {
    	freopen("seq.in","r",stdin); freopen("seq.out","w",stdout);
    	RI i,j; for (F.read(n),i=1;i<=n;++i)
    	for (F.read(k),j=1,lst=0;j<=k;lst=x,++j)
    	F.read(x),vis[x]=1,lst&&(addedge(lst,x),0),mx=max(mx,x);
    	for (i=1;i<=mx;++i) if (vis[i]&&!deg[i]) q.push(i);
    	while (!q.empty())
    	{
    		int now=q.top(); q.pop(); printf("%d ",now);
    		for (i=head[now];i;i=e[i].nxt)
    		if (!(--deg[e[i].to])) q.push(e[i].to);
    	}
    	return 0;
    }
    

    试剂

    计数题要么考虑DP要么考虑拆贡献,要么两个一起用

    我们考虑乘法很难通过计算方案数来求贡献,因此我们考虑如何避免

    枚举(i),表示先将(i)个数做乘法操作,然后再与其他数进行加法,此时我们如果算出方案数显然就是它的贡献

    我们发现此时数被分成了两类,一类是我们强制选的只进行乘法的数(叫做(A)类),另一类是可以随便选的数(叫做(B)

    我们可以设(f_{i,j})表示(i)(A)类数和(j)(B)类数的操作方案数,转移很简单但是也有挺多细节

    然后预处理出(g_i)表示有(i)个数相乘的所有方案数的和,因此答案就是(sum_{i=1}^n g_i imes f_{i,n-i})

    DP的转移细节看代码,复杂度(O(n^2))

    #include<cstdio>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=3005;
    int n,mod,f[N][N],g[N],x,ans;
    inline void inc(int& x,CI y)
    {
    	if ((x+=y)>=mod) x-=mod;
    }
    int main()
    {
    	freopen("reagent.in","r",stdin); freopen("reagent.out","w",stdout);
    	RI i,j; for (scanf("%d%d",&n,&mod),g[0]=i=1;i<=n;++i)
    	for (scanf("%d",&x),j=i;j;--j) inc(g[j],1LL*g[j-1]*x%mod);
    	for (f[1][0]=i=1;i<=n;++i) for (j=0;j<=n;++j)
    	{
    		if (j) inc(f[i][j],1LL*i*j%mod*f[i][j-1]%mod);
    		if (j>1) inc(f[i][j],1LL*j*(j-1)%mod*f[i][j-1]%mod);
    		if (i>1) inc(f[i][j],1LL*i*(i-1)/2LL%mod*f[i-1][j]%mod);
    	}
    	for (i=1;i<=n;++i) inc(ans,1LL*g[i]*f[i][n-i]%mod);
    	return printf("%d",ans),0;
    }
    

    立体计算几何

    首先先求出能覆盖所有点的最小长方体,由此我们可以很容易地判断是否合法

    考虑接下来就是判断一个询问是CLOSED还是UNKNOWN了,我们考虑对于已知的最小长方体进行扩展,使得要询问的点恰好在其边界上,然后询问新的长方体中是否有不在立方体内的点即可

    因此问题本质就是个三维数点,两个$log $应该是过不去的,但是由于有特殊性质可以优化

    考虑我们给(x)维和询问离线,以(y)维的值为下标,(z)维的值为存储值建一棵线段树,因此现在的问题就是要求在给定(x,y)维的信息后,一个区间([z_1,z_2])中是否存在不在长方体内的点

    可以通过在线段树上维护最小的(>z_1)的值以及最大的(<z_2)的值来实现询问,复杂度就是(O(nlog n))的了

    以下是陈指导的代码(细节真多不想写)

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 500000
    #define K 1000000
    using namespace std;
    int n,m,k,xm,ym,zm,x1,x2,Y1,y2,z1,z2,ans[N+5];
    struct P
    {
    	int x,y,z;I P(CI a=0,CI b=0,CI c=0):x(a),y(b),z(c){}
    	I bool operator < (Con P& o) Con {return x^o.x?x<o.x:(y^o.y?y<o.y:z<o.z);}
    }p[N+5];
    struct Q
    {
    	int p,x,y,z;I Q(CI id=0,CI a=0,CI b=0,CI c=0):p(id),x(a),y(b),z(c){}
    	I bool operator < (Con Q& o) Con {return x^o.x?x<o.x:(y^o.y?y<o.y:z<o.z);}
    }q[K+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define D isdigit(c=tc())
    		char c,*A,*B,FI[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		#undef D
    }F;
    map<P,int> V;I void asdf()
    {
    	RI i,x,y,z;for(puts("CORRECT"),i=1;i<=m;++i) V[p[i]]=1;
    	for(i=1;i<=k;++i) F.read(x),F.read(y),F.read(z),puts(V[P(x,y,z)]?"CLOSED":"UNKNOWN");
    }
    I void Check()
    {
    	RI i;for(i=1;i<=m;++i) if(x1<=p[i].x&&p[i].x<=x2&&
    		Y1<=p[i].y&&p[i].y<=y2&&z1<=p[i].z&&p[i].z<=z2) puts("INCORRECT"),exit(0);
    	puts("CORRECT");
    }
    int y3,y4;
    class SegmentTree
    {
    	private:
    		#define PT CI l=1,CI r=ym,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		#define PU(x) (Mn[x]=min(Mn[x<<1],Mn[x<<1|1]),Mx[x]=max(Mx[x<<1],Mx[x<<1|1]))
    		int Mn[N<<2],Mx[N<<2];
    	public:
    		I void Init(PT) {if(Mn[rt]=zm+1,Mx[rt]=0,l==r) return;RI mid=l+r>>1;Init(LT),Init(RT);}
    		I void U(CI y,CI z,PT)
    		{
    			if(l==r) return (void)(z>=z1&&(Mn[rt]=min(Mn[rt],z)),z<=z2&&(Mx[rt]=max(Mx[rt],z)));
    			RI mid=l+r>>1;y<=mid?U(y,z,LT):U(y,z,RT),PU(rt);
    		}
    		I bool Q(CI L,CI R,CI U,CI D,PT)
    		{
    			if(L<=l&&r<=R) return (Mn[rt]>D&&Mx[rt]<U);RI mid=l+r>>1;
    			return (L<=mid?Q(L,R,U,D,LT):1)&&(R>mid?Q(L,R,U,D,RT):1);
    		}
    }S;
    I int Qry(CI y,CI z) {return S.Q(min(Y1,y),max(y2,y),min(z1,z),max(z2,z))-1;}
    int main()
    {
    	freopen("zyqh.in","r",stdin),freopen("zyqh.out","w",stdout);
    	RI i,j,t,x,y,z;F.read(xm),F.read(ym),F.read(zm),F.read(n),F.read(m),F.read(k),x1=xm,Y1=ym,z1=zm;
    	for(i=1;i<=n;++i) F.read(x),F.read(y),F.read(z),
    		x1=min(x1,x),x2=max(x2,x),Y1=min(Y1,y),y2=max(y2,y),z1=min(z1,z),z2=max(z2,z);
    	for(i=1;i<=m;++i) F.read(p[i].x),F.read(p[i].y),F.read(p[i].z);sort(p+1,p+m+1);
    	if(!n) return asdf(),0;Check();
    	for(i=1;i<=k;++i) F.read(q[i].x),F.read(q[i].y),F.read(q[i].z),q[i].p=i;sort(q+1,q+k+1);
    	RI l=0,r=m+1;W(l^m&&p[l+1].x<x1) ++l;W(r^1&&p[r-1].x>x2) --r;
    	RI a=0,b=k+1;W(a^k&&q[a+1].x<x1) ++a;W(b^1&&q[b-1].x>x2) --b;
    	#define C(i) (x1<=q[i].x&&q[i].x<=x2&&Y1<=q[i].y&&q[i].y<=y2&&z1<=q[i].z&&q[i].z<=z2&&(ans[q[i].p]=1))
    	for(S.Init(),i=l+1;i<=r-1;++i) S.U(p[i].y,p[i].z);
    	for(i=a+1;i<=b-1;++i) !C(i)&&(ans[q[i].p]=Qry(q[i].y,q[i].z));
    	for(S.Init(),i=l+1;i<=r-1;++i) S.U(p[i].y,p[i].z);for(i=a,t=l;i>=1;--i)
    		{W(t>=1&&p[t].x>=q[i].x) S.U(p[t].y,p[t].z),--t;!C(i)&&(ans[q[i].p]=Qry(q[i].y,q[i].z));}
    	for(S.Init(),i=l+1;i<=r-1;++i) S.U(p[i].y,p[i].z);for(i=b,t=r;i<=k;++i)
    		{W(t<=m&&p[t].x<=q[i].x) S.U(p[t].y,p[t].z),++t;!C(i)&&(ans[q[i].p]=Qry(q[i].y,q[i].z));}
    	for(i=1;i<=k;++i) puts(ans[i]?(~ans[i]?"OPEN":"CLOSED"):"UNKNOWN");return 0;
    }
    

    Postscript

    陈指导是我们的红太阳!!!

  • 相关阅读:
    2018-8-10-如何写毕业论文-表格
    2018-8-10-win10-uwp-自定义控件初始化
    2018-8-10-win10-uwp-自定义控件初始化
    hashMap的hashCode() 和equal()的使用
    java中fail-fast 和 fail-safe的区别
    java各种集合的线程安全
    Java集合框架总结—超详细-适合面试
    CodeForces 1058C C. Vasya and Golden Ticket
    CodeForces 1058C C. Vasya and Golden Ticket
    CodeForces-1058B B. Vasya and Cornfield
  • 原文地址:https://www.cnblogs.com/cjjsb/p/13726863.html
Copyright © 2020-2023  润新知