zoukankan      html  css  js  c++  java
  • 10.21 牛客提高集训营6


    2018.10.21 牛客提高集训营6

    比赛链接

    不是很懂那些粘人代码还直接交上去的人,在提交记录里很好看么?

    A 最长路(拓扑 分层)

    题目链接

    容易想到建反图拓扑。有了最长路后,按最长路对图分层。
    因为当前点路径字典序最小,就是要满足第一条边最小后,再满足下一个点路径字典序最小。后者可以直接用上一层的答案。
    按这两个关键字排序,就可以得到当前层的路径字典序排名了。
    复杂度(O(nlog n))

    比较两条路径字典序大小,因为处理到(x)时,前面的转移都确定了,所以也可以倍增+Hash找出第一个不同字符。。

    //505ms	78300KB
    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    #define mp std::make_pair
    #define pr std::pair<int,int>
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    #define mod 998244353
    #define Mod(x) x>=mod&&(x-=mod)
    typedef long long LL;
    const int N=1e6+5,INF=2e9;
    
    int dgr[N];
    pr A[N];
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Graph
    {
    	int Enum,H[N],nxt[N],to[N],len[N];
    	void AE(int u,int v,int w)
    	{
    		to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, len[Enum]=w;
    	}
    }G,R;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline bool cmp(int a,int b)
    {
    	return A[a]<A[b];
    }
    void Toposort(int n,int m)
    {
    	static int q[N],f[N],rk[N],sum[N];
    	static bool vis[N];
    	static std::vector<int> v[N];
    
    	int h=0,t=0;
    	for(int i=1; i<=n; ++i) if(!dgr[i]) q[++t]=i;
    	while(h<t)
    	{
    		int x=q[++h];
    		vis[x]=1, v[f[x]].push_back(x), A[x]=mp(INF,0);
    		for(int i=R.H[x],v; i; i=R.nxt[i])
    		{
    			f[v=R.to[i]]=std::max(f[v],f[x]+1);
    			if(!--dgr[v]) q[++t]=v;
    		}
    	}
    
    	for(int i=1; i<=n; ++i)
    	{
    		if(!v[i].size()) break;
    		int l=v[i].size();
    		std::vector<int> &vi=v[i];
    		for(int j=0; j<l; ++j)
    		{
    			int x=vi[j]; pr t;
    			for(int k=G.H[x],v; k; k=G.nxt[k])
    				if(f[x]==f[v=G.to[k]]+1 && (t=mp(G.len[k],rk[v]))<A[x])
    					A[x]=t, sum[x]=29ll*sum[v]%mod+t.first, Mod(sum[x]);
    		}
    		std::sort(vi.begin(),vi.end(),cmp);
    		for(int j=0; j<l; ++j) rk[vi[j]]=j;
    	}
    
    	for(int i=1; i<=n; ++i)
    		if(vis[i]) printf("%d
    ",(int)(29ll*sum[i]%mod));
    		else puts("Infinity");
    }
    
    int main()
    {
    	int n=read(),m=read();
    	for(int i=1,u,v,w; i<=m; ++i)
    		u=read(),v=read(),w=read(),++dgr[u],G.AE(u,v,w),R.AE(v,u,w);
    	Toposort(n,m);
    
    	return 0;
    }
    

    B 选择题(DP 期望 退背包)

    题目链接

    (x)个人的期望得分为:$$sum_{mx=1}^4sum_{cx=1}^4w_{mx,cx}cdot p(x,mx,cx)$$

    (cx)表示(x)选了哪个选项,(p(x,mx,cx))表示在(cnt(mx)>lfloorfrac n2 floor)时,(x)选了(cx)的概率。
    那么对(cx)分类讨论,(f(x,mx,cnt))表示除(x)外,恰好有(cnt)个人选了(mx)的概率。则有$$p(x,mx,cx)=egin{cases}p_{x,cx}sum_{i=lfloorfrac n2 floor}f(x,mx,i),& cx=mxp_{x,cx}sum_{i=lfloorfrac n2 floor+1}f(x,mx,i),& cx eq mxend{cases}$$

    (f(x,mx,cnt))的转移就是个背包。枚举(x),就可以(O(n^3))了。期望得分(55)
    我们发现(x)变成(x+1)时,对(f)的影响时,加入一个元素(x)并删掉(x+1)的影响。先拿所有人算一遍(f),加入一个人就是做一遍(O(n))的DP。把(f)的转移反过来就可以(O(n))删掉(x)的贡献了:

    [f_{i,j}=(1-p_{i,mx})f_{i-1,j}+p_{i,mx}f_{i-1,j-1}\ f_{i-1,j}=frac{f_{i,j}-p_{i,mx}f_{i-1,j-1}}{1-p_{i,mx}}]

    (j)(0)的时候特判。注意(p)(1)的时候也要特判。
    复杂度(O(n^2))

    //226ms	536KB
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define gc() getchar()
    #define mod 998244353
    #define Mod(x) x>=mod&&(x-=mod)
    typedef long long LL;
    const int N=2005;
    
    int P[N][4],W[4][4],f[N],g[N];
    LL Ans[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline int Inv(int x,int k=mod-2)
    {
    	int t=1;
    	for(; k; k>>=1,x=1ll*x*x%mod)
    		if(k&1) t=1ll*t*x%mod;
    	return t;
    }
    void Solve(int n,int mx)
    {
    	memset(f,0,sizeof f);
    	f[0]=1;
    	for(int i=1; i<=n; ++i)
    	{
    		LL p=P[i][mx];
    		for(int j=i; j; --j)
    			f[j]=p*f[j-1]%mod+(1-p)*f[j]%mod, Mod(f[j]);//就是(mod+)1-p啊(mod-p是-p)
    		f[0]=(1-p)*f[0]%mod;
    	}
    	for(int i=1; i<=n; ++i)//x
    	{
    		LL p=P[i][mx];
    		if(p!=1)
    		{
    			LL inv=Inv(mod+1-p);
    			g[0]=inv*f[0]%mod;
    			for(int j=1; j<=n; ++j) g[j]=inv*(f[j]-p*g[j-1]%mod)%mod;
    		}
    		else
    		{
    			for(int j=0; j<n; ++j) g[j]=f[j+1];//f[i-1][j-1]=f[i][j]
    			g[n]=0;
    		}
    		LL tmp=0;
    		for(int j=(n>>1)+1; j<=n; ++j) tmp+=g[j];
    		tmp%=mod;
    		for(int j=0; j<4; ++j) Ans[i]+=1ll*W[mx][j]*P[i][j]%mod*(tmp+(mx==j?g[n>>1]:0))%mod;//cx
    	}
    }
    
    int main()
    {
    	int n=read();
    	for(int i=1; i<=n; ++i)
    		P[i][0]=read(),P[i][1]=read(),P[i][2]=read(),P[i][3]=read();
    	for(int i=0; i<4; ++i)
    		W[i][0]=read(),W[i][1]=read(),W[i][2]=read(),W[i][3]=read();
    	for(int mx=0; mx<4; ++mx) Solve(n,mx);
    	for(int i=1; i<=n; ++i) printf("%d
    ",(int)((Ans[i]%mod+mod)%mod));
    
    	return 0;
    }
    

    C 树(树链剖分)

    题目链接

    是不是写出这题,树剖就无敌了啊。。
    写完啦!感觉还好,也就6k嘛。

    肯定要用点来表示边的颜色,然后树剖。
    对于操作2,我们可以拆成:
    1.将u->v路径上的点,所有连向子节点的边染成col2;
    2.将u->v路径上的点,所有连向父节点的边染成col1;
    3.将LCA(u,v)连向父节点的边染成col2。
    那么本题的操作实际有四种:链修改、链查询、修改一条链上所有连向子节点的边、换根+子树修改。
    除了链修改指向子节点的边,其它都是树剖模板(换根见BZOJ3083)。
    因为是改所有指向子节点的边,所以也可以树剖维护。用to_son[x]表示x指向儿子的轻边的颜色,用另一棵线段树维护(注意只是轻边,重边要单独在第一棵树上改)。
    除此之外,在第一棵线段树上维护每个点x到fa[x]的边的颜色。
    这样查询时,对于重链可以直接在第一棵线段树上查;对于轻边(top[x]->fa[top[x]])的颜色,需要区分是第一棵树上top[x]的值还是第二棵树上fa[top[x]]的值。修改时再带一个时间优先级即可。
    要修改的链是一样的,且to_son[x]只会单点查(切换重链时)(也是单点修改),所以只要一棵线段树同时维护两种标记就行了。
    复杂度(O(mlog^2n))
    另外单点查完全可以用非递归。
    边界(dfn+/-1)问题要注意。(会不会还有锅啊。。)

    //358ms	20428KB
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define fir first
    #define sec second
    #define mp std::make_pair
    #define pr std::pair<int,int>//time val
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=1e5+5;
    
    int n,Enum,H[N],nxt[N<<1],to[N<<1],fa[N],dep[N],sz[N],son[N],top[N],dfn[N],Index,ref[N],out[N];
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Segment_Tree
    {
    	#define ls rt<<1
    	#define rs rt<<1|1
    	#define lson l,m,ls
    	#define rson m+1,r,rs
    	#define S N<<2
    	int cnt[S][3],sz[S];
    	pr tag1[S],tag2[S];
    	#undef S
    
    	#define Update(rt) cnt[rt][0]=cnt[ls][0]+cnt[rs][0], cnt[rt][1]=cnt[ls][1]+cnt[rs][1], cnt[rt][2]=cnt[ls][2]+cnt[rs][2]
    	#define Cov1(rt,v) cnt[rt][0]=0, cnt[rt][1]=0, cnt[rt][2]=0, cnt[rt][v.sec]=sz[rt], tag1[rt]=v
    	#define Cov2(rt,v) tag2[rt]=v
    	inline void PushDown(int rt)
    	{
    		int l=ls,r=rs;
    		if(tag1[rt].fir) Cov1(l,tag1[rt]), Cov1(r,tag1[rt]), tag1[rt].fir=0;
    		if(tag2[rt].fir) Cov2(l,tag2[rt]), Cov2(r,tag2[rt]), tag2[rt].fir=0;
    	}
    	void Build(int l,int r,int rt)
    	{
    		cnt[rt][0]=sz[rt]=r-l+1;
    		if(l!=r)
    		{
    			int m=l+r>>1;
    			Build(lson), Build(rson);
    		}
    	}
    	void ModifyI(int l,int r,int rt,int L,int R,pr v)//为了常数 粘了仨Modify→_→
    	{
    		if(L<=l && r<=R) {Cov1(rt,v); return;}
    		PushDown(rt);
    		int m=l+r>>1;
    		if(L<=m) ModifyI(lson,L,R,v);
    		if(m<R) ModifyI(rson,L,R,v);
    		Update(rt);
    	}
    	void Modify1(int l,int r,int rt,int p,pr v)
    	{
    		if(l==r) {Cov1(rt,v); return;}
    		PushDown(rt);
    		int m=l+r>>1;
    		p<=m ? Modify1(lson,p,v) : Modify1(rson,p,v);
    		Update(rt);
    	}
    	void Modify2(int l,int r,int rt,int L,int R,pr v1,pr v2)
    	{
    		if(L<=l && r<=R) {Cov1(rt,v1), Cov2(rt,v2); return;}
    		PushDown(rt);
    		int m=l+r>>1;
    		if(L<=m) Modify2(lson,L,R,v1,v2);
    		if(m<R) Modify2(rson,L,R,v1,v2);
    		Update(rt);
    	}
    	pr QueryP(int l,int r,int rt,int p,int id)
    	{
    		int m;
    		while(l!=r)
    		{
    			PushDown(rt);
    			m=l+r>>1, p<=m?(r=m,rt=ls):(l=m+1,rt=rs);
    		}
    		return id==1?tag1[rt]:tag2[rt];
    	}
    	int QueryI(int l,int r,int rt,int L,int R,int c)
    	{
    		if(L<=l && r<=R) return cnt[rt][c];
    		PushDown(rt);
    		int m=l+r>>1;
    		if(L<=m)
    			if(m<R) return QueryI(lson,L,R,c)+QueryI(rson,L,R,c);
    			else return QueryI(lson,L,R,c);
    		return QueryI(rson,L,R,c);
    	}
    }T;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline void AE(int u,int v)
    {
    	to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
    	to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
    }
    inline int Jump(int u,int lca)
    {
    	int las=u;
    	while(top[u]!=top[lca]) u=fa[las=top[u]];
    	return u==lca?las:ref[dfn[lca]+1];
    }
    void DFS1(int x)
    {
    	int mx=0; sz[x]=1;
    	for(int i=H[x],v; i; i=nxt[i])
    		if((v=to[i])!=fa[x])
    		{
    			fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
    			if(sz[v]>mx) mx=sz[v], son[x]=v;
    		}
    }
    void DFS2(int x,int tp)
    {
    	top[x]=tp, dfn[x]=++Index, ref[Index]=x;
    	if(son[x])
    	{
    		DFS2(son[x],tp);
    		for(int i=H[x],v; i; i=nxt[i])
    			if((v=to[i])!=fa[x]&&v!=son[x]) DFS2(v,v);
    	}
    	out[x]=Index;
    }
    int Query(int u,int v,int c)
    {
    	int ans=0,tp;
    	while(top[u]!=top[v])
    	{
    		if(dep[top[u]]<dep[top[v]]) std::swap(u,v);
    		tp=top[u];
    		if(dfn[tp]<dfn[u]) ans+=T.QueryI(1,n,1,dfn[tp]+1,dfn[u],c);
    		pr t1=T.QueryP(1,n,1,dfn[tp],1),t2=T.QueryP(1,n,1,dfn[fa[tp]],2);
    		ans+=t1.fir>t2.fir?(t1.sec==c):(t2.sec==c);
    		u=fa[tp];
    	}
    	if(dep[u]<dep[v]) std::swap(u,v);
    	if(dfn[v]<dfn[u]) ans+=T.QueryI(1,n,1,dfn[v]+1,dfn[u],c);
    	return ans;
    }
    void Modify(int u,int v,int c1,int c2,int t)
    {
    	if(dfn[u]<n) T.Modify1(1,n,1,dfn[u]+1,mp(t,c2));//dfn[son[u]]
    	if(dfn[v]<n) T.Modify1(1,n,1,dfn[v]+1,mp(t,c2));//这个修改就不会有冲突了 
    	while(top[u]!=top[v])
    	{
    		if(dep[top[u]]<dep[top[v]]) std::swap(u,v);
    		T.Modify2(1,n,1,dfn[top[u]],dfn[u],mp(t+1,c1),mp(t,c2));
    		u=fa[top[u]];
    		T.Modify1(1,n,1,dfn[u]+1,mp(t+1,c2));
    	}
    	if(dep[u]<dep[v]) std::swap(u,v);
    	T.Modify2(1,n,1,dfn[v],dfn[u],mp(t+1,c1),mp(t,c2));
    	T.Modify1(1,n,1,dfn[v],mp(t+1,c2));
    }
    
    int main()
    {
    	n=read();
    	for(int i=1; i<n; ++i) AE(read(),read());
    	DFS1(1), DFS2(1,1), T.Build(1,n,1);
    	for(int opt,x,y,c,c2,rt,Q=read(),i=1; i<=Q; ++i)
    		switch(opt=read())
    		{
    			case 1: x=read(),y=read(),printf("%d
    ",Query(x,y,read())); break;
    			case 2: x=read(),y=read(),c=read(),c2=read(),Modify(x,y,c,c2,i<<1); break;
    			case 3:
    			{
    				rt=read(),x=read(),c=read();
    				if(x==rt) T.ModifyI(1,n,1,1,n,mp(i<<1,c));
    				else if(dfn[x]<=dfn[rt]&&dfn[rt]<=out[x])
    				{
    					y=Jump(rt,x), T.ModifyI(1,n,1,1,dfn[y]-1,mp(i<<1,c));
    					if(out[y]<n) T.ModifyI(1,n,1,out[y]+1,n,mp(i<<1,c));
    				}
    				else if(dfn[x]<out[x]) T.ModifyI(1,n,1,dfn[x]+1,out[x],mp(i<<1,c));
    				break;
    			}
    		}
    
    	return 0;
    }
    

    考试代码

    A

    傻了,一直不会统计答案,只要把两个关键字的顺序一换就行了啊QAQ。

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define mp std::make_pair
    #define pr std::pair<int,int>
    #define gc() getchar()
    #define MAXIN 300000
    //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    #define mod 998244353
    #define Mod(x) x>=mod&&(x-=mod)
    typedef long long LL;
    const int N=1e6+5;
    
    int n,m,outd[N],ind[N],pw[N];
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Graph
    {
    	int Enum,H[N],nxt[N],to[N],len[N];
    	void AE(int u,int v,int w)
    	{
    		to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, len[Enum]=w;
    	}
    }G,R;
    struct Node
    {
    	int id;
    	pr x;
    	inline bool operator <(const Node &a)const
    	{
    		return x<=a.x;
    	}
    }A[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    void Toposort()
    {
    	static int q[N],f[N],lev[N],lev2[N],pre[N],sum[N],dgr[N];
    	static bool inq[N],vis[N];
    
    	int h=0,t=0;
    	memcpy(dgr,outd,sizeof dgr);
    	for(int i=1; i<=n; ++i) if(!dgr[i]) q[++t]=i;
    	while(h<t)
    	{
    		int x=q[++h]; inq[x]=1;
    		for(int i=R.H[x],v; i; i=R.nxt[i])
    		{
    			f[v=R.to[i]]=std::max(f[v],f[x]+1);
    			if(!--dgr[v]) q[++t]=v;
    		}
    	}
    
    	memset(lev,0x3f,sizeof lev);
    	memcpy(dgr,ind,sizeof dgr);
    	h=0,t=0;
    	for(int i=1; i<=n; ++i) if(!dgr[i]) q[++t]=i,lev[i]=1,lev2[i]=1;
    	int Gap=t;
    	while(h<t)
    	{
    		if(h==Gap)
    		{
    			for(int i=h+1; i<=t; ++i) A[i]=(Node){q[i],mp(lev[q[i]],pre[q[i]])}, lev2[q[i]]=lev[q[i]];
    			std::sort(A+h+1,A+t+1);
    			int tmp=1; lev[A[h+1].id]=1;
    			for(int i=h+2; i<=t; ++i)
    				if(A[i].x!=A[i-1].x) lev[A[i].id]=++tmp;
    				else lev[A[i].id]=tmp;
    //			for(int i=h+1; i<=t; ++i)
    //				printf("%d:id:%d lev:%d pre:%d
    ",i,A[i].id,lev[A[i].id],pre[A[i].id]); puts("");
    			Gap=t;
    		}
    		int x=q[++h];
    		for(int i=G.H[x],v; i; i=G.nxt[i])
    		{
    			if(f[v=G.to[i]]+1==f[x])
    			{
    				if(lev[v]>lev[x])
    					lev[v]=lev[x], pre[v]=G.len[i];//, sum[v]=sum[x]*29%mod+pre[v], Mod(sum[v]);
    				else if(lev[v]==lev[x]&&pre[v]>G.len[i])
    					pre[v]=G.len[i];//, sum[v]=sum[x]*29%mod+pre[v], Mod(sum[v]);
    //				printf("v:%d lev[v]=%d pre[v]=%d pw[%d]=%d
    ",v,lev[v],pre[v],f[v],pw[f[v]]);
    			}
    			if(!--dgr[v]) q[++t]=v;
    		}
    	}
    //	puts("");
    //	for(int i=1; i<=n; ++i) printf("%d:lev:%d lev2:%d pre:%d
    ",i,lev[i],lev2[i],pre[i]); puts("");
    
    	memcpy(dgr,outd,sizeof dgr);
    	h=0,t=0;
    	for(int i=1; i<=n; ++i) if(!dgr[i]) q[++t]=i;
    	while(h<t)
    	{
    		int x=q[++h];
    		for(int i=R.H[x],v; i; i=R.nxt[i])
    		{
    			if(f[v=R.to[i]]==f[x]+1 && lev2[v]==lev2[x] && pre[x]==R.len[i])
    				sum[v]=sum[x]*29%mod+pre[x], Mod(sum[v]);
    			if(!--dgr[v]) q[++t]=v;
    		}
    	}
    
    	for(int i=1; i<=n; ++i)
    		if(inq[i]) printf("%d
    ",(int)(1ll*sum[i]*29%mod));
    		else puts("Infinity");
    }
    
    int main()
    {
    //	freopen("A1.in","r",stdin);
    //	freopen(".out","w",stdout);
    
    	n=read(),m=read();
    	pw[0]=1;
    	for(int i=1; i<=n; ++i) pw[i]=1ll*pw[i-1]*29%mod;
    	for(int i=1,u,v,w; i<=m; ++i) u=read(),v=read(),w=read(),++outd[u],++ind[v],G.AE(u,v,w),R.AE(v,u,w);
    	Toposort();
    
    	return 0;
    }
    
  • 相关阅读:
    web安全之ssrf
    web安全之sql注入布尔注入
    web安全之sql注入报错型注入
    web安全之sqlload_file()和into outfile()
    浅谈 FHQ-Treap
    (菜鸟都能看懂的)网络最大流最小割,Ford-Fulkerson及Dinic详解
    浅谈最小生成树
    浅谈强连通分量(Tarjan)
    DP-DAY3游记
    关于01背包问题
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9826829.html
Copyright © 2011-2022 走看看