• 2019.03.14 ZJOI2019模拟赛 解题报告


    得分: (100+100+0=200)(T1)在最后(2)分钟写了出来,(T2)在最后(10)分钟写了出来,反而(T3)写了(4)个小时爆(0)

    (T1):风王结界

    一道数学题,看完题解是无比的简单。

    比赛时最后两分钟把式子凑出来了((RP)爆表)。。。

    题解详见这篇博客:【CF660E】Different Subsets For All Tuples(组合数学),即这题模数为(10^9+7)的版本。

    下面直接给出代码:

    #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 1000000
    #define Qinv(x) Qpow(x,X-2)
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int n,m,X;
    I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}//快速幂
    int main()
    {
    	freopen("invisible.in","r",stdin),freopen("invisible.out","w",stdout);
    	RI i,ans,p1,p2,b1,b2;
    	scanf("%d%d%d",&n,&m,&X),ans=p1=Qpow(m,n),p2=1,b1=Qinv(m),b2=(1LL*2*m-1)%X;//初始化
    	for(i=0;i^n;++i) Inc(ans,1LL*p1*p2%X),p1=1LL*p1*b1%X,p2=1LL*p2*b2%X;//O(n)计算答案
    	return printf("%d",ans),0;//输出答案
    }
    

    (T2):此世全部之恶

    手写(bitset)暴力卡过。。。

    显然,前两个限制随便判即可,关键在于第三个限制。

    考虑当矩阵中只有(0,1)时,我们可以用(n)(bitset)来存下每一行的值。

    对于每一对(i,j),按位或一下第(i)行和第(j)行的(bitset)

    如果(a_{i,j}=1),且按位或得到的结果中存在某一位为(0)(即第(i)行和第(j)行上这一位皆为(0),也就是最大值为(0)),则输出(NO),否则输出(YES)

    而这个做法显然可以根据一个常见的套路进行推广。

    我们先初始化所有(bitset)所有值为(0)

    然后倒序枚举元素值,每次把值等于这个元素的位置在(bitset)中将值改为(1)

    每次改完之后,就按前面提到过的方法(Check)一遍即可。

    这个做法的时间复杂度是(O(frac{n^3}{32})),用(C++)自带的(STL)肯定过不去,于是就要手写+小卡常。

    然后就能过了(主要是这题正解虽是(O(n^2))却常数很大,因此这种暴力做法也能卡过)。

    代码如下:

    #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 2000
    #define V 10000
    #define uint unsigned int
    #define pb push_back
    #define mp make_pair
    #define fir first
    #define sec second
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n,a[N+5][N+5];vector<pair<int,int> > v[V+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define tn (x<<3)+(x<<1)
    		#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=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    class Bitset//手写bitset
    {
    	private:
    		static Con int SZ=64;uint a[SZ];
    	public:
    		I Bitset() {memset(a,0,sizeof(a));}I void Set(CI x) {a[x>>5]|=1ull<<(x&31);}
    		I bool operator | (Con Bitset& x) Con//求两个bitset按位或之后是否存在某一位为0
    		{
    			static uint Sz=n-1>>5,Mx=(1ull<<((n-1)&31)+1)-1;
    			for(RI i=0;i^Sz;++i) if(~(a[i]|x.a[i])) return true;//判断对于前面完整的数字,是否存在某一位为0
    			return (a[Sz]|x.a[Sz])^Mx;//判断最后一个不完整的数字是否存在某一位为0
    		}
    }s[N+5];
    int main()
    {
    	freopen("grail.in","r",stdin),freopen("grail.out","w",stdout);
    	RI i,j,k,sz,Mx=0;for(F.read(n),i=1;i<=n;++i) for(j=1;j<=n;++j) F.read(a[i][j]),Gmax(Mx,a[i][j]),v[a[i][j]].pb(mp(i-1,j-1));//读入,按值存储下每一个位置
    	for(i=1;i<=n;++i) {for(j=1;j^i;++j) if(a[i][j]^a[j][i]) return puts("NO"),0;if(a[i][i]) return puts("NO"),0;}//对于题目中的前两种限制进行判断
    	for(i=Mx;~i;--i)//倒序枚举元素值
    	{
    		for(sz=v[i].size(),j=0;j^sz;++j) s[v[i][j].fir].Set(v[i][j].sec);//把值等于这个元素的位置在bitset中将值改为1
    		for(j=0;j^sz;++j) (s[v[i][j].fir]|s[v[i][j].sec])&&(puts("NO"),exit(0),0);//如果按位或得到的结果中存在某一位为0,则输出NO
    	}return puts("YES"),0;//输出YES
    }
    

    (T3):俄刻阿诺斯

    我们可以设从根节点到(x)号节点的路径上最小的高度(Min_x)

    则我们先将(B_i)排个序,然后统计出对于每个(B_i),有多少个(Min_xge B_i),记作(g_i)

    则不难发现,若对于每个(B_i),都满足(g_ige n-i+1),即(g_i-n+i-1ge0),就存在一种放下所有棒子的方式。

    然后我们就可以用线段树维护(g_i-i)的最小值,然后二分答案,枚举在哪个点加,并用线段树进行验证即可。

    然而这种做法复杂度其实是有一定问题的。。。

    理论上来讲时间复杂度是(O(nlognlog10^8)),而这貌似已经(TLE)了。

    所以,把我这份卡常一个晚上、最慢的点仍要(3)秒多的代码贴一下:

    #pragma GCC optimize(2)
    #pragma G++ optimize(2)
    #pragma GCC optimize(3)
    #pragma G++ optimize(3)
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #pragma GCC optimize("-fgcse")
    #pragma GCC optimize("-fgcse-lm")
    #pragma GCC optimize("-fipa-sra")
    #pragma GCC optimize("-ftree-pre")
    #pragma GCC optimize("-ftree-vrp")
    #pragma GCC optimize("-fpeephole2")
    #pragma GCC optimize("-ffast-math")
    #pragma GCC optimize("-fsched-spec")
    #pragma GCC optimize("unroll-loops")
    #pragma GCC optimize("-falign-jumps")
    #pragma GCC optimize("-falign-loops")
    #pragma GCC optimize("-falign-labels")
    #pragma GCC optimize("-fdevirtualize")
    #pragma GCC optimize("-fcaller-saves")
    #pragma GCC optimize("-fcrossjumping")
    #pragma GCC optimize("-fthread-jumps")
    #pragma GCC optimize("-funroll-loops")
    #pragma GCC optimize("-fwhole-program")
    #pragma GCC optimize("-freorder-blocks")
    #pragma GCC optimize("-fschedule-insns")
    #pragma GCC optimize("inline-functions")
    #pragma GCC optimize("-ftree-tail-merge")
    #pragma GCC optimize("-fschedule-insns2")
    #pragma GCC optimize("-fstrict-aliasing")
    #pragma GCC optimize("-fstrict-overflow")
    #pragma GCC optimize("-falign-functions")
    #pragma GCC optimize("-fcse-skip-blocks")
    #pragma GCC optimize("-fcse-follow-jumps")
    #pragma GCC optimize("-fsched-interblock")
    #pragma GCC optimize("-fpartial-inlining")
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-freorder-functions")
    #pragma GCC optimize("-findirect-inlining")
    #pragma GCC optimize("-fhoist-adjacent-loads")
    #pragma GCC optimize("-frerun-cse-after-loop")
    #pragma GCC optimize("inline-small-functions")
    #pragma GCC optimize("-finline-small-functions")
    #pragma GCC optimize("-ftree-switch-conversion")
    #pragma GCC optimize("-foptimize-sibling-calls")
    #pragma GCC optimize("-fexpensive-optimizations")
    #pragma GCC optimize("-funsafe-loop-optimizations")
    #pragma GCC optimize("inline-functions-called-once")
    #pragma GCC optimize("-fdelete-null-pointer-checks")
    #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 200000
    #define INF 1e8
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    #define min(x,y) ((x)<(y)?(x):(y))
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    using namespace std;
    int n,m,ee,h[N+5],a[N+5],lnk[N+5];struct edge {int to,nxt;}e[N<<1];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define tn (x<<3)+(x<<1)
    		#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=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    class SegmentTreeSolver
    {
    	private:
    		#define GP(x) (lower_bound(a+1,a+m+1,(x)+1)-a-1)
    		#define Give(x,y) (h[y]<=h[Mn[x]]?(Mn[y]=y,SMn[y]=Mn[x]):(Mn[y]=Mn[x],SMn[y]=h[y]<=h[SMn[x]]?y:SMn[x]))
    		#define Link(x,y) (nxt[x]=lk[y],lk[y]=x)
    		int p[N+5],p_[N+5],fa[N+5],Mn[N+5],SMn[N+5],lk[N+5],nxt[N+5];
    		class SegmentTree//线段树
    		{
    			private:
    				#define STO l,hl,rt<<1
    				#define ORZ hl+1,r,rt<<1|1
    				#define PU(x) (Mn[x]=min(Mn[x<<1],Mn[x<<1|1]))
    				#define PD(x) (F[x]&&(Mn[x<<1]+=F[x],F[x<<1]+=F[x],Mn[x<<1|1]+=F[x],F[x<<1|1]+=F[x],F[x]=0))
    				int n,Mn[N<<2],F[N<<2];
    				void bld(CI l,CI r,CI rt) {if(!(l^r)) return (void)(Mn[rt]=-n+l-1);int hl=l+r>>1;bld(STO),bld(ORZ),PU(rt);}//建树,初始化每个点的权值
    			public:
    				I void Init(CI t) {bld(1,n=t,1);}I bool Check() {return Mn[1]>=0;}
    				I void Update(CI p,CI v)//修改(为卡常将其写成了非递归)
    				{
    					if(!p) return;static int l,r,hl,rt;l=1,r=n,hl,rt=1;
    					W(r>p) PD(rt),hl=l+r>>1,p<=hl?(r=hl,rt<<=1):(Mn[rt<<1]+=v,F[rt<<1]+=v,l=hl+1,rt=rt<<1|1);
    					Mn[rt]+=v,F[rt]+=v;W(rt>>=1) PU(rt);
    				}
    				#undef STO
    				#undef ORZ
    		}T;
    		void dfs(CI x) {for(int i=lnk[x];i;i=e[i].nxt) e[i].to^fa[x]&&(fa[e[i].to]=x,Give(x,e[i].to),dfs(e[i].to),0);}//DFS预处理
    		I bool Check(CI x,CI v)//验证答案
    		{
    			static int i,res;for(i=lk[x];i;i=nxt[i]) T.Update(p[i],-1),T.Update(p_[i]=GP(min(h[x]+v,h[SMn[i]])),1);//修改
    			for(res=T.Check(),i=lk[x];i;i=nxt[i]) T.Update(p[i],1),T.Update(p_[i],-1);return res;//记录是否合法后,把前面改过的改回去
    		}
    	public:
    		I void Solve()
    		{
    			m>n&&(puts("-1"),exit(0),0),sort(a+1,a+m+1),h[0]=INF,dfs(Mn[1]=1),T.Init(m);
    			RI i,STO,hl,ORZ,f,ans=INF;for(i=1;i<=n;++i) T.Update(p[i]=GP(h[Mn[i]]),1),Link(i,Mn[i]);T.Check()&&(puts("0"),exit(0),0);//初始化求出g[i]
    			STO=1,ORZ=INF;W(STO<=ORZ) {for(f=0,i=1;i<=n&&!f;++i) Check(i,hl=STO+ORZ>>1)&&(f=1);f?(ans=hl,ORZ=hl-1):STO=hl+1;}//二分
    			ans==INF?puts("-1"):printf("%d",ans);//输出答案
    		}
    }S;
    int main()
    {
    	freopen("oceanus.in","r",stdin),freopen("oceanus.out","w",stdout);
    	RI i,x,y;for(F.read(n),i=1;i<=n;++i) F.read(h[i]);for(i=1;i^n;++i) F.read(x,y),add(x,y),add(y,x);//读入数据
    	for(F.read(m),i=1;i<=m;++i) F.read(a[i]);return S.Solve(),0;//读入数据
    }
    
  • 相关阅读:
    Android6.0-运行时权限处理
    Notification的基本用法以及使用RemoteView实现自定义布局
    Android Apk的反编译和加密
    SurfaceView的基本使用
    Java8部分新特性的学习
    Android的UI调优
    Builder模式详解及其在Android开发中的应用
    hex(x) 将整数x转换为16进制字符串
    oct(x) 将一个数字转化为8进制
    sum(iterable[, start]) 对集合求和
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Contest20190314.html
Copyright © 2020-2023  润新知