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

    这次考试,题目比较有难度,考场上我只有T1有65分的思路,T3有一个暴力的思路,T2完全不会打,但是这次我把自己应该得到的分数都拿到了,也算是一个进步吧。

    T1 Dove 打扑克

    这道题,考试时我想到可以用一个权值线段树的思想,查询当前位置之前的与当前数值差值为 x的数的个数,每次重构一颗线段树 nlogn 进行计算,但是这只能拿到65分,算法的瓶颈在于我每次都重构了一颗线段树,我当时想半天如何才能不重构树,但没什么思路,那么正解就和我的思路不太一样,正解是维护了两个东西,size[i],表示 i 位置的大小,cnt[i] 表示这个大小的数量,那么我们就可以通过这两个数组,再利用一个前缀和就可以 o(qn) 得到结果,但是这样只能得到80分,因为我们还可以再优化,介绍一个引理:
    给定n个非负整数组成的可重集合,{x1,...,xn},满足\(\sum\limits_{i=1}^{n}x_i=m\),那么一定有
    \(diff_x\) <=\(sqrt(m)\), \(diff_x\)表示集合中本质不同的数字的数量。
    知道了这个结论,那么这道题就可以进行优化了,因为当前人数不同的组的数量不超过\(sqrt(n)\),所以我们可以使用一个set单点插入,删除,并在查询过程中使用一个vector,记录前缀和,这样我们就可以AC了,总复杂度 \(o\times sqrt(n) \times log(sqrt(n))\)
    代码如下:

    65pts_code
    
    
    #include<bits/stdc++.h>
    #define re register int
    #define ii inline int
    #define iv inline void
    #define lc (rt<<1)
    #define rc (rt<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    const int N=201000;
    int n,m,ans;
    int size[N],be[N],vis[N];
    bool no[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 gett(int x)
    {
    	if(x==be[x])
    		return x;
    	return be[x]=gett(be[x]);
    }
    struct Segment_Tree
    {
    	int sum[360010];
    	iv pp(int rt)
    	{
    		sum[rt]=sum[lc]+sum[rc];
    	}
    	iv insert(int rt,int l,int r,int p)
    	{
    		if(l==r)
    		{
    			sum[rt]++;
    			return;
    		}
    		if(mid>=p)
    			insert(lc,l,mid,p);
    		else
    			insert(rc,mid+1,r,p);
    		pp(rt);
    	}
    	ii query(int rt,int l,int r,int L,int R)
    	{
    		if(L>R)
    			return 0;
    		if(L<=l&&r<=R)
    			return sum[rt];
    		if(mid>=R)
    			return query(lc,l,mid,L,R);
    		if(mid<L)
    			return query(rc,mid+1,r,L,R);
    		return query(lc,l,mid,L,R)+query(rc,mid+1,r,L,R);
    	}
    	iv ql(int rt,int l,int r)
    	{
    		sum[rt]=0;
    		if(l==r)
    			return;
    		ql(lc,l,mid);
    		ql(rc,mid+1,r);
    	}
    }T;
    signed main()
    {
    	int opt,x,y,fx,fy,fi;
    	n=read();
    	m=read();
    	for(re i=1;i<=n;i++)
    		size[i]=1;
    	for(re i=1;i<=n;i++)
    		be[i]=i;
    	while(m--)
    	{
    		opt=read();
    		if(opt==1)
    		{
    			x=read();
    			y=read();
    			fx=gett(x);
    			fy=gett(y);
    			if(fx==fy)
    				continue;
    			be[fy]=fx;
    			size[fx]+=size[fy];
    			size[fy]=0;
    		}
    		else
    		{
    			T.ql(1,1,n);
    			x=read();
    			ans=0;
    			if(x!=0)
    			{
    				for(re i=1;i<=n;i++)
    				{
    					
    					fi=gett(i);
    					if(vis[fi]==m)
    						continue;
    					ans+=T.query(1,1,n,size[fi]+x,n);
    					if(size[fi]-x>0)
    						ans+=T.query(1,1,n,1,size[fi]-x);
    					T.insert(1,1,n,size[fi]);
    					vis[fi]=m;
    				}
    			}
    			else
    			{
    				for(re i=1;i<=n;i++)
    				{
    					
    					fi=gett(i);
    					if(vis[fi]==m)
    						continue;
    					ans+=T.query(1,1,n,size[fi],n);
    					ans+=T.query(1,1,n,1,size[fi]-1);
    					T.insert(1,1,n,size[fi]);
    					vis[fi]=m;
    				}
    			}
    			printf("%d\n",ans);
    		}
    	}
    	return 0;
    }
    
    
    AC_code
    
    
    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define ii inline int
    #define iv inline void
    #define lc (rt<<1)
    #define rc (rt<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    const int N=201000;
    struct node
    {
    	int posi,sum;
    	friend bool operator < (node a,node b)
    	{
    		return a.posi < b.posi;
    	}
    };
    set<int> T;
    int n,m,ans;
    int size[N],be[N],vis[N],cnt[N],p[N];
    bool no[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 gett(int x)
    {
    	if(x==be[x])
    		return x;
    	return be[x]=gett(be[x]);
    }
    signed main()
    {
    	int opt,x,y,z,fx,fy,fi,zero;
    	n=read();
    	m=read();
    	T.insert(1);
    	cnt[1]=n;
    	for(re i=1;i<=n;i++)
    	{
    		be[i]=i;
    		size[i]=1;	
    	}
    	while(m--)
    	{
    		ans=0;
    		opt=read();
    		if(opt==1)
    		{
    			x=read();
    			y=read();
    			fx=gett(x);
    			fy=gett(y);
    			if(fx==fy)
    				continue;		
    			cnt[size[fx]]--;
    			cnt[size[fy]]--;
    			if(!cnt[size[fx]])
    				T.erase(size[fx]);
    			if(!cnt[size[fy]])
    				T.erase(size[fy]);
    			size[fx]+=size[fy];
    			if(T.find(size[fx])==T.end())
    				T.insert(size[fx]);
    			cnt[size[fx]]++;
    			be[fy]=fx;
    			size[fy]=0;	
    		}
    		else
    		{
    			x=read();
    			zero=0;
    			if(x==0)
    			{
    				int col=0;
    				for(auto pos:T)
    				{
    					ans+=zero*cnt[pos];
    					ans+=(cnt[pos])*(cnt[pos]-1)/2;
    					zero+=cnt[pos];
    				}
    			}
    			else
    			{
    				vector<node>v;
    				for(auto pos:T)
    				{
    					zero+=cnt[pos];
    					v.push_back((node){pos,zero});
    					if(pos>x)
    					{
    						int o=upper_bound(v.begin(),v.end(),(node){pos-x,0})-v.begin();
    						if(o-1>=0)
    							ans+=v[o-1].sum*cnt[pos];
    					}
    				}
    			}	
    			printf("%lld\n",ans);		
    		}
    	}
    	return 0;
    }
    
    

    T2 Cicada 与排序

    思路:我们设\(f_{i,j,k}\),表示第 i 层,原来的位置为 j ,排序后的位置为 k 的概率,那么答案很好求。现在的问题是如何进行状态转移,我们引入一个辅助数组\(g_{i,j}\)表示归并排序过程中两个指针分别指向i,j的概率,那么我们根据归并排序的过程进行转移即可。具体实现见代码:

    AC_code
    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define ii inline int
    #define iv inline void
    #define lc (rt<<1)
    #define rc (rt<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    const int mo=998244353;
    const int inv=499122177;
    const int N=510;
    int n;
    int a[N];
    int f[N][N][N],g[N][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);
    }
    iv merge(int rt,int l,int r)
    {
    	if(l==r)
    	{
    		f[rt][l][r]=1;
    		return;
    	}
    	merge(rt+1,l,mid);
    	merge(rt+1,mid+1,r);
    	memset(g,0,sizeof(g));
    	g[0][0]=1;
    	for(re i=0;i<=mid-l+1;i++)
    	{
    		for(re j=0;j<=r-mid;j++)
    		{
    			if(i==mid-l+1)
    				g[i][j+1]=(g[i][j+1]%mo+g[i][j]%mo)%mo;
    			else if(j==r-mid)
    				g[i+1][j]=(g[i+1][j]%mo+g[i][j]%mo)%mo;
    			else if(a[l+i]>a[mid+j+1])
    				g[i][j+1]=(g[i][j+1]%mo+g[i][j]%mo)%mo;
    			else if(a[l+i]<a[mid+j+1])
    				g[i+1][j]=(g[i+1][j]%mo+g[i][j]%mo)%mo;
    			else
    			{
    				g[i][j+1]=(g[i][j+1]%mo+g[i][j]%mo*inv%mo)%mo;
    				g[i+1][j]=(g[i+1][j]%mo+g[i][j]%mo*inv%mo)%mo;
    			}	
    		}
    	}
    	for(re i=l;i<=r;i++)
    	{
    		for(re j=0;j<=mid-l+1;j++)
    		{
    			for(re k=0;k<=r-mid;k++)
    			{
    				if(j==mid-l+1 and k==r-mid)
    					continue;
    				if(j==mid-l+1)
    					f[rt][i][j+l+k]=(f[rt][i][j+l+k]+f[rt+1][i][mid+k+1]%mo*g[j][k]%mo)%mo;
    				else if(k==r-mid)
    					f[rt][i][j+l+k]=(f[rt][i][j+l+k]+f[rt+1][i][j+l]%mo*g[j][k]%mo)%mo;
    				else if(a[j+l]>a[mid+k+1])
    					f[rt][i][j+l+k]=(f[rt][i][j+l+k]+f[rt+1][i][mid+k+1]%mo*g[j][k]%mo)%mo;
    				else if(a[j+l]<a[mid+k+1])
    					f[rt][i][j+l+k]=(f[rt][i][j+l+k]+f[rt+1][i][j+l]%mo*g[j][k]%mo)%mo;
    				else
    				{
    					f[rt][i][j+l+k]=(f[rt][i][j+l+k]+f[rt+1][i][j+l]%mo*g[j][k]%mo*inv%mo)%mo;
    					f[rt][i][j+l+k]=(f[rt][i][j+l+k]+f[rt+1][i][mid+k+1]%mo*g[j][k]%mo*inv%mo)%mo;
    				}
    			}
    		}
    	}
    	sort(a+l,a+r+1);
    }
    signed main()
    {
    	n=read();
    	for(re i=1;i<=n;i++)
    		a[i]=read();
    	merge(1,1,n);
    	for(re i=1;i<=n;i++)
    	{
    		int ans=0;
    		for(re j=1;j<=n;j++)
    			ans=(ans%mo+f[1][i][j]%mo*j%mo)%mo;
    		printf("%lld ",ans);
    	}
    	return 0;
    }
    
    

    T3 Cicada 拿衣服

    思路:\(n^2\)暴力+乱搞,首先说一下暴力,我们以每个点为左端点向右查询满足条件的右端点,然后每次都进行一次更新答案的过程,这样就可以拿到64分,然后进行乱搞,猜测答案不会很大,于是我们枚举的右端点就到 i+700 ,即可通过此题......

    AC_code
    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    #define ii inline int
    #define iv inline void
    #define lc (rt<<1)
    #define rc (rt<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    const int N=1010000;
    const int INF=1e9;
    int n,k;
    int ans[N],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);
    }
    iv spe_1()
    {
    	for(re i=1;i<=n;i++)
    	{
    		int minn=INF,maxx=0,Or=0,And=(1<<30)-1,r=-INF;
    		for(re j=i;j<=n;j++)
    		{
    			Or|=a[j];
    			And&=a[j];
    			if(a[j]>maxx)
    				maxx=a[j];
    			if(a[j]<minn)
    				minn=a[j];
    			if(minn-maxx+Or-And>=k)
    				r=j;
    		}
    		int len=r-i+1;
    		for(re j=i;j<=r;j++)
    			if(ans[j]<len)
    				ans[j]=len;
    	}
    }
    iv spe_2()
    {
    	for(re i=1;i<=n;i++)
    	{
    		int minn=INF,maxx=0,Or=0,And=(1<<30)-1,r=-INF;
    		for(re j=i;j<=min(n,700+i);j++)
    		{
    			Or|=a[j];
    			And&=a[j];
    			if(a[j]>maxx)
    				maxx=a[j];
    			if(a[j]<minn)
    				minn=a[j];
    			if(minn-maxx+Or-And>=k)
    				r=j;
    		}
    		int len=r-i+1;
    		for(re j=i;j<=r;j++)
    			if(ans[j]<len)
    				ans[j]=len;
    	}
    }
    signed main()
    {
    	n=read();
    	k=read();
    	for(re i=1;i<=n;i++)
    	{
    		a[i]=read();
    		ans[i]=-1;
    	}
    	if(n<=30000)
    		spe_1();
    	else
    		spe_2();
    	for(re i=1;i<=n;i++)
    		printf("%lld ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    Windows phone开发 网络编程之HttpWebRequest
    ASP.NET AJAX应用
    Web程序安全机制
    SQLCE本地数据库
    Web服务
    LINQ数据库技术
    windows phone媒体应用开发
    ASP.NET文件操作
    ASP.NET XML文件
    centos6.5安装配置fastdfs+nginx实现分布式图片服务器
  • 原文地址:https://www.cnblogs.com/WindZR/p/15130408.html
Copyright © 2011-2022 走看看