zoukankan      html  css  js  c++  java
  • noip模拟测试33

    这次考试,我犯了一个错误,刚开始把题面看了一遍,当时觉得应该 1,3 ,2 开题,于是就大力搞T1,把T2仍到了最后,最后也没时间写了,结果T2差不多是一道线段树裸题,但是我当时没看出来,知道考试结束前几分钟才想到一个接近正解的思路,但是没时间打了,主要原因有两点:1是之前做过一道类似的题,但是我没什么印象,显然那道题不是靠自己调出来的,以后要避免这种情况,自己多思考,2是自己对于线段树合并的认识和掌握不是很扎实,自己理解了半天才重新弄明白线段树合并到底是什么,所以对于之前学过的知识点要抽空复习。

    T1 Hunter

    这道题考试的时候我打了一个暴搜,也是对于这种同时有分子和分母的暴搜的一次尝试,但是我当时忘记了期望的线性性,分数累加的时候我每次都进行通分,结果数据很毒瘤,一个点都没过,全都爆了 long long ,结束后听从varuxn的建议对于结果直接进行累加,取模,拿到了自己预估的25分暴力,但是听说利用状压+记忆化可以得到45分。

    思路:1 号猎人死亡的轮数等于在 1 号之前死亡的猎人数 +1, 根据期望的线性性, 就等于每个猎人比 1 号猎人先死的概率和, 不难发现第 i 个猎人比 1号猎人先死的概率是\(\frac{w_i}{w_i+w_1}\),直接一遍 for 循环即可

    25pts_code
    
    
    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define iv inline void
    #define ii inline int
    using namespace std;
    const int mo=998244353;
    const int N=1e5+10;
    int n,sum;
    int a[N];
    bool vis[110];
    struct node
    {
    	int up,down;
    };
    ii read()
    {
    	int x=0;
    	bool f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-')
    			f=0;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return f?x:(-x);
    }
    ii ksm(int d,int z)
    {
    	int out=1;
    	while(z)
    	{
    		if(z&1)
    			out=out*d%mo;
    		z>>=1;
    		d=d%mo*d%mo;
    	}
    	return out%mo;
    }
    int dfs(int p,int cnt,int u,int d,int now)
    {
    	if(cnt==n)
    		return (u%mo)*(cnt%mo)%mo*(ksm(d,mo-2)%mo)%mo;
    	int nu=0,nd=0,nval=0;
    	nval=(a[1]%mo)*(cnt%mo)%mo*(ksm(now,mo-2)%mo)%mo;
    	
    	for(re i=1;i<=n;i++)
    	{
    		if(!vis[i])
    		{
    			vis[i]=1;
    			int use=dfs(i,cnt+1,a[i],now,now-a[i]);
    			nval=(nval%mo)+(use%mo)%mo;
    			vis[i]=0;
    		}
    	}
    	return (u%mo)*(ksm(d,mo-2)%mo)%mo*(nval%mo)%mo;
    }
    signed main()
    {
    	n=read();
    	for(re i=1;i<=n;i++)
    	{
    		a[i]=read();
    		sum+=a[i];
    	}
    	if(n==1)
    	{
    		printf("1\n");
    		return 0;
    	}
    	int sd=sum,su=a[1],ans=su%mo*(ksm(sum,mo-2)%mo)%mo;
    	for(re i=2;i<=n;i++)
    	{	
    		memset(vis,0,sizeof(vis));
    		vis[1]=1;
    		vis[i]=1;
    		int use=dfs(i,2,a[i],sum,sum-a[i]);
    		ans=ans%mo+(use%mo)%mo;
    	}
    	printf("%lld\n",(ans%mo+mo)%mo);
    	return 0;
    }
    
    
    AC_code
    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define iv inline void
    #define ii inline int
    using namespace std;
    const int mo=998244353;
    const int N=1e5+10;
    int n,sum;
    int a[N];
    ii read()
    {
    	int x=0;
    	bool f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-')
    			f=0;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return f?x:(-x);
    }
    ii ksm(int d,int z)
    {
    	int out=1;
    	while(z)
    	{
    		if(z&1)
    			out=out*d%mo;
    		z>>=1;
    		d=d%mo*d%mo;
    	}
    	return out%mo;
    }
    signed main()
    {
    	n=read();
    	for(re i=1;i<=n;i++)
    		a[i]=read();
    	int ans=0;
    	for(re i=2;i<=n;i++)
    		ans=(ans%mo)+(a[i]%mo*(ksm(a[1]+a[i],mo-2)%mo)%mo)%mo;
    	printf("%lld\n",(ans%mo+mo)%mo+1);
    	return 0;
    }
    
    

    T2 Defence

    这道题是我挺失败的一道题,上面已经说了,但是这道题比较简单,考完后我又复习了一遍线段树合并,这道题思路就是假设 L 是前缀 0 的数量, R 是后缀 0 的数量, M 是最长的连续 0 的数量, 显然,答案就是\(max(L+R,M)\),直接上线段树维护即可,但是注意,我刚开始对于动态开点理解没有透彻,刚开始build出了所有点,导致TLE,解决方案就是写真正的动态开点,对于没有出现过的节点直接利用信息,就是在那份 TLE的代码上改一改,那份代码比较清晰,AC代码就是把pushup函数里分情况讨论一下,建议先阅读TLE代码。

    TLE_code
    #include<bits/stdc++.h>
    #define re register int
    #define ii inline int
    #define iv inline void
    #define mid ((l+r)>>1)
    #define head heeeadd
    #define next neeete
    using namespace std;
    const int N=1e5+10;
    int n,m,q,tot,timi;
    int to[N<<1],head[N],next[N<<1],root[N],out[N];
    ii read()
    {
    	int x=0;
    	bool f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-')
    			f=0;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return f?x:(-x);
    }
    struct Segment_Tree
    {
    	int maxl[N*40],maxr[N*40],maxm[N*40];
    	int lr[N*40],rl[N*40],ml[N*40],mr[N*40];
    	int lc[N*40],rc[N*40];
    	iv pp(int rt,int l,int r)
    	{
    		#define lc lc[rt]
    		#define rc rc[rt]
    		maxl[rt]=maxl[lc];
    		maxr[rt]=maxr[rc];
    		lr[rt]=lr[lc];
    		rl[rt]=rl[rc];
    		if(maxl[lc]==mid-l+1)
    		{
    			maxl[rt]=maxl[lc]+maxl[rc];
    			lr[rt]=lr[rc];
    		}
    		if(maxr[rc]==r-mid)
    		{
    			maxr[rt]=maxr[rc]+maxr[lc];
    			rl[rt]=rl[lc];
    		}
    		maxm[rt]=maxm[lc];
    		ml[rt]=ml[lc];
    		mr[rt]=mr[lc];
    		if(maxm[rc]>maxm[lc])
    		{
    			maxm[rt]=maxm[rc];
    			ml[rt]=ml[rc];
    			mr[rt]=mr[rc];
    		}
    		if(maxr[lc]+maxl[rc]>maxm[rt])
    		{
    			maxm[rt]=maxr[lc]+maxl[rc];
    			ml[rt]=rl[lc];
    			mr[rt]=lr[rc];
    		}
    		#undef lc
    		#undef rc
    	}
    	ii insert(int rt,int l,int r,int p)
    	{
    		#define lc lc[rt]
    		#define rc rc[rt]
    		if(!rt)
    			rt=++timi;
    		if(l==r)
    		{
    			maxl[rt]=maxr[rt]=maxm[rt]=0;
    			lr[rt]=l-1;
    			rl[rt]=l+1;
    			ml[rt]=l+1;
    			mr[rt]=l-1;
    			return rt;
    		}
    		if(mid>=p)
    			lc=insert(lc,l,mid,p);
    		else
    			rc=insert(rc,mid+1,r,p);
    		pp(rt,l,r);
    		#undef lc
    		#undef rc
    		return rt;
    	}
    	ii build(int rt,int l,int r)
    	{
    		#define lc lc[rt]
    		#define rc rc[rt]
    		if(!rt)
    			rt=++timi;
    		maxl[rt]=maxr[rt]=maxm[rt]=r-l+1;
    		lr[rt]=r;
    		rl[rt]=l;
    		ml[rt]=l;
    		mr[rt]=r;
    		if(l==r)
    			return rt;
    		lc=build(lc,l,mid);
    		rc=build(rc,mid+1,r);
    		pp(rt,l,r);
    		#undef lc
    		#undef rc
    		return rt;
    	}
    	ii merge(int p,int q,int l,int r)
    	{
    		if((!p)||(!q))
    			return p+q;
    		if(l==r)
    		{
    			if(!maxm[q])
    			{
    				maxl[p]=maxr[p]=maxm[p]=0;
    				lr[p]=l-1;
    				rl[p]=l+1;
    				ml[p]=l+1;
    				mr[p]=l-1;
    			}
    			return p;
    		}
    		lc[p]=merge(lc[p],lc[q],l,mid);
    		rc[p]=merge(rc[p],rc[q],mid+1,r);
    		pp(p,l,r);
    		return p;
    	}
    	ii query(int rt,int l,int r)
    	{
    		return max(maxl[rt]+maxr[rt],maxm[rt]);
    	}
    }T;
    iv add(int x,int y)
    {
    	to[++tot]=y;
    	next[tot]=head[x];
    	head[x]=tot;
    }
    iv dfs(int st)
    {
    	for(re i=head[st];i;i=next[i])
    	{
    		int p=to[i];
    		dfs(p);
    		root[st]=T.merge(root[st],root[p],1,m);			
    	}
    	out[st]=T.query(root[st],1,m);
    }
    int main()
    {
    	n=read();
    	m=read();
    	q=read();
    	int u,v;
    	for(re i=1;i<n;i++)
    	{
    		u=read();
    		v=read();
    		add(u,v);
    	}
    	for(re i=1;i<=n;i++)
    		root[i]=T.build(root[i],1,m);
    	for(re i=1;i<=q;i++)
    	{
    		u=read();
    		v=read();
    		root[u]=T.insert(root[u],1,m,v);
    	}
    	dfs(1);
    	for(re i=1;i<=n;i++)
    		if(T.maxm[root[i]]!=m) printf("%d\n",out[i]);
    		else printf("-1\n");
    	return 0;
    }
    
    
    AC_code
    
    
    #include<bits/stdc++.h>
    #define re register int
    #define ii inline int
    #define iv inline void
    #define mid ((l+r)>>1)
    #define head heeeadd
    #define next neeete
    using namespace std;
    const int N=1e5+10;
    int n,m,q,tot,timi;
    int to[N<<1],head[N],next[N<<1],root[N],out[N];
    ii read()
    {
    	int x=0;
    	bool f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-')
    			f=0;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return f?x:(-x);
    }
    struct Segment_Tree
    {
    	int maxl[N*40],maxr[N*40],maxm[N*40];
    	int lr[N*40],rl[N*40],ml[N*40],mr[N*40];
    	int lc[N*40],rc[N*40];
    	iv pp(int rt,int l,int r)
    	{
    		#define lc lc[rt]
    		#define rc rc[rt]
    		if(lc and rc)
    		{
    			maxl[rt]=maxl[lc];
    			maxr[rt]=maxr[rc];
    			lr[rt]=lr[lc];
    			rl[rt]=rl[rc];
    			if(maxl[lc]==mid-l+1)
    			{
    				maxl[rt]=maxl[lc]+maxl[rc];
    				lr[rt]=lr[rc];
    			}
    			if(maxr[rc]==r-mid)
    			{
    				maxr[rt]=maxr[rc]+maxr[lc];
    				rl[rt]=rl[lc];
    			}
    			maxm[rt]=maxm[lc];
    			ml[rt]=ml[lc];
    			mr[rt]=mr[lc];
    			if(maxm[rc]>maxm[lc])
    			{
    				maxm[rt]=maxm[rc];
    				ml[rt]=ml[rc];
    				mr[rt]=mr[rc];
    			}
    			if(maxr[lc]+maxl[rc]>maxm[rt])
    			{
    				maxm[rt]=maxr[lc]+maxl[rc];
    				ml[rt]=rl[lc];
    				mr[rt]=lr[rc];
    			}
    		}
    		else if(lc)
    		{
    			maxl[rc]=(r-mid);
    			maxr[rc]=(r-mid);
    			maxm[rc] =(r-mid);
    			ml[rc] =mid+1;
    			mr[rc] =r;
    			lr[rc] =r;
    			rl[rc] =(mid+1);
    			
    			maxl[rt]=maxl[lc];
    			maxr[rt]=maxr[rc];
    			lr[rt]=lr[lc];
    			rl[rt]=rl[rc];
    			if(maxl[lc]==mid-l+1)
    			{
    				maxl[rt]=maxl[lc]+maxl[rc];
    				lr[rt]=lr[rc];
    			}
    			if(maxr[rc]==r-mid)
    			{
    				maxr[rt]=maxr[rc]+maxr[lc];
    				rl[rt]=rl[lc];
    			}
    			maxm[rt]=maxm[lc];
    			ml[rt]=ml[lc];
    			mr[rt]=mr[lc];
    			if(maxm[rc]>maxm[lc])
    			{
    				maxm[rt]=maxm[rc];
    				ml[rt]=ml[rc];
    				mr[rt]=mr[rc];
    			}
    			if(maxr[lc]+maxl[rc]>maxm[rt])
    			{
    				maxm[rt]=maxr[lc]+maxl[rc];
    				ml[rt]=rl[lc];
    				mr[rt]=lr[rc];
    			}
    			maxl[rc]=0;
    			maxr[rc]=0;
    			maxm[rc] =0;
    			ml[rc] =0;
    			mr[rc] =0;
    			lr[rc] =0;
    			rl[rc] =0;
    		}
    		else if(rc)
    		{
    			maxl[lc]=mid-l+1;
    			maxr[lc]=mid-l+1;
    			maxm[lc] =mid-l+1;
    			ml[lc] =l;
    			mr[lc] =mid;
    			lr[lc] =mid;
    			rl[lc] =l;
    			
    			maxl[rt]=maxl[lc];
    			maxr[rt]=maxr[rc];
    			lr[rt]=lr[lc];
    			rl[rt]=rl[rc];
    			if(maxl[lc]==mid-l+1)
    			{
    				maxl[rt]=maxl[lc]+maxl[rc];
    				lr[rt]=lr[rc];
    			}
    			if(maxr[rc]==r-mid)
    			{
    				maxr[rt]=maxr[rc]+maxr[lc];
    				rl[rt]=rl[lc];
    			}
    			maxm[rt]=maxm[lc];
    			ml[rt]=ml[lc];
    			mr[rt]=mr[lc];
    			if(maxm[rc]>maxm[lc])
    			{
    				maxm[rt]=maxm[rc];
    				ml[rt]=ml[rc];
    				mr[rt]=mr[rc];
    			}
    			if(maxr[lc]+maxl[rc]>maxm[rt])
    			{
    				maxm[rt]=maxr[lc]+maxl[rc];
    				ml[rt]=rl[lc];
    				mr[rt]=lr[rc];
    			}
    			
    			maxl[lc]=0;
    			maxr[lc]=0;
    			maxm[lc] =0;
    			ml[lc] =0;
    			mr[lc] =0;
    			lr[lc] =0;
    			rl[lc] =0;
    		}
    		#undef lc
    		#undef rc
    		
    	}
    	ii insert(int rt,int l,int r,int p)
    	{
    		#define lc lc[rt]
    		#define rc rc[rt]
    		if(!rt)
    			rt=++timi;
    		if(l==r)
    		{
    			maxl[rt]=maxr[rt]=maxm[rt]=0;
    			lr[rt]=l-1;
    			rl[rt]=l+1;
    			ml[rt]=l+1;
    			mr[rt]=l-1;
    			return rt;
    		}
    		if(mid>=p)
    			lc=insert(lc,l,mid,p);
    		else
    			rc=insert(rc,mid+1,r,p);
    		pp(rt,l,r);
    		#undef lc
    		#undef rc
    		return rt;
    	}
    	ii merge(int p,int q,int l,int r)
    	{
    		if((!p)||(!q))
    			return p+q;
    		if(l==r)
    		{
    			if(!maxm[q])
    			{
    				maxl[p]=maxr[p]=maxm[p]=0;
    				lr[p]=l-1;
    				rl[p]=l+1;
    				ml[p]=l+1;
    				mr[p]=l-1;
    			}
    			return p;
    		}
    		lc[p]=merge(lc[p],lc[q],l,mid);
    		rc[p]=merge(rc[p],rc[q],mid+1,r);
    		pp(p,l,r);
    		return p;
    	}
    	ii query(int rt,int l,int r)
    	{
    		return max(maxl[rt]+maxr[rt],maxm[rt]);
    	}
    }T;
    iv add(int x,int y)
    {
    	to[++tot]=y;
    	next[tot]=head[x];
    	head[x]=tot;
    }
    iv dfs(int st)
    {
    	for(re i=head[st];i;i=next[i])
    	{
    		int p=to[i];
    		dfs(p);
    		root[st]=T.merge(root[st],root[p],1,m);			
    	}
    	out[st]=T.query(root[st],1,m);
    }
    int main()
    {
    	n=read();
    	m=read();
    	q=read();
    	int u,v;
    	for(re i=1;i<n;i++)
    	{
    		u=read();
    		v=read();
    		add(u,v);
    	}
    	for(re i=1;i<=q;i++)
    	{
    		u=read();
    		v=read();
    		root[u]=T.insert(root[u],1,m,v);
    	}
    	dfs(1);
    	for(re i=1;i<=n;i++)
    		if(root[i]) printf("%d\n",out[i]);
    		else printf("-1\n");
    	return 0;
    }
    
    

    T3 connect

    一道状压好题,思路是:1 号点到 N 的路径唯一相当于存在一条 1 到 N 的链, 并且不在链上的每个联通块最多只和链上的一个点有连边.考虑状压 DP, 记录当前考虑的点集和链的末端点, 转移有两种, 一种是让链的长度增加 1, 另一种是添加一个点集并接到当前链的末端点.那我们设 \(f_{i,j}\)表示当前点集为i,结尾为j的最大长度的总长度之和,\(val_{i,j}\)表示 i,j 之间的边权,\(sum_i\)表示状态为i的边权之和,\(bu_{i,j}\)表示在集合i中,与j相连的边权之和,那么可以得到这样的状态转移方程:
    \(f_{i,j|(1<<k-1)}=max(f_{1,j|(1<<k-1)},f_{i,j}+val_j,k)\) (连到末尾)
    \(f_{i|k,j}=max(f_{i|k,j},f_{i,j}+bu_{k,j}+sum_k)\)
    代码如下:

    AC_code
    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define ii inline int
    #define iv inline void
    using namespace std;
    int n,m,tot,S;
    int f[1<<17][20];
    int val[20][20],sum[1<<17],bu[1<<17][20];
    ii read()
    {
    	int x=0;
    	bool f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-')
    			f=0;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return f?x:(-x);
    }
    signed main()
    {
    	n=read();
    	m=read();
    	S=1<<n;
    	int u,v,w;
    	memset(val,-1,sizeof(val));
    	for(re i=1;i<=m;i++)
    	{
    		u=read();
    		v=read();
    		w=read();
    		val[u][v]=val[v][u]=w;
    	}
    	for(re i=1;i<S;i++)
    	{
    		for(re j=1;j<=n;j++)
    		{
    			if((i>>(j-1))&1)
    			{
    				for(re k=j+1;k<=n;k++)
    				{
    					if(((i>>(k-1))&1) and (val[j][k]!=-1))
    						sum[i]+=val[j][k];
    				}	
    			}
    			else
    			{
    				for(re k=1;k<=n;k++)
    				{
    					if(k==j)
    						continue;
    					if(((i>>(k-1))&1) and (val[j][k]!=-1))
    						bu[i][j]+=val[j][k];
    				}
    			}
    		}
    	}
    	for(re i=1;i<S;i++)
    	{
    		if(!(i&1))	continue;
    		for(re j=1;j<=n;j++)
    		{
    			if(!((i>>(j-1))&1)) continue;
    			for(re k=1;k<=n;k++)
    			{
    				if(!((i>>(k-1))&1) and val[j][k]!=-1)
    					f[i|(1<<(k-1))][k]=max(f[i|(1<<(k-1))][k],f[i][j]+val[j][k]);
    			}
    			for(re k=(S-1)^i;k;k=(k-1)&((S-1)^i))
    				f[i|k][j]=max(f[i|k][j],f[i][j]+sum[k]+bu[k][j]);
    		}
    	}
    	printf("%lld\n",sum[S-1]-f[S-1][n]);
    	return 0;
    }
    
    
  • 相关阅读:
    CodeForces 1294B Collecting Packages(排序+贪心)
    计算系数(组合数)
    垒骰子(矩阵快速幂)
    蒜头君倒水(矩阵快速幂)
    Buy Tickets POJ
    Billboard HDU
    树状数组求逆序对 附HDU1394
    codeforces 1304D Shortest and Longest LIS
    codeforces 1301C Ayoub's function
    Codeforces 1301B Motarack's Birthday(二分)
  • 原文地址:https://www.cnblogs.com/WindZR/p/15116265.html
Copyright © 2011-2022 走看看