noip模拟测试23

时间:2021-07-25
本文章向大家介绍noip模拟测试23,主要包括noip模拟测试23使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

考试总结:这次考试,成绩和自己的预估分数差距有点大,问题主要是出在了第一题上,我当时读完题,就想到了线段树,很快就码完了,但是我当时没有想到的两个关键问题是:1.没有想到离散化 2.对于异或的情况没有分类讨论,导致我第一题爆零,其他的题还好,基本上拿到了自己预估的分数。这次考试的教训就是对于自己认为想到的正解多想想一些细节问题,不能想到啥就打啥。

T1 联

思路:很显然,一道线段树裸题,我的算法是记录每个区间的1的数量之和,最后查询的时候只需要按照先左后右的顺序查询当前区间里1的数量和区间长度的大小即可,但是注意对于异或的操作进行分类讨论,具体实现见代码:

#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=1e7+10;
const int M=1e6+10;
int m,ty,ul,ur,cnt;
int lsh[M];
vector<int> v[N];
struct CUN
{
	int sum,lazy;
}use[N<<2];
struct Segment_tree
{
    iv pp(int rt)
    {
        use[rt].sum=use[lc].sum+use[rc].sum;
    }
    iv pd(int rt,int l,int r)
    {
        if(use[rt].lazy)
        {
            if(use[rt].lazy==1)
            {
                 use[lc].lazy=use[rc].lazy=use[rt].lazy;
                 use[lc].sum=mid-l+1;
                 use[rc].sum=r-mid;
            }
            else if(use[rt].lazy==2)
            {
                use[lc].lazy=use[rc].lazy=use[rt].lazy;
                use[lc].sum=0;
                use[rc].sum=0;
            }
            else 
            {
                if(use[lc].lazy==1)
                {
                    use[lc].lazy=2;
                    use[lc].sum=0;
                }
                else if(use[lc].lazy==2)
                {
                    use[lc].lazy=1;
                    use[lc].sum=mid-l+1;
                }
                else if(use[lc].lazy==3)
                {
                    use[lc].lazy=0;
                    use[lc].sum=mid-l+1-use[lc].sum;
                }
                else
                {
                    use[lc].lazy=3;
                    use[lc].sum=mid-l+1-use[lc].sum;
                }

                if(use[rc].lazy==1)
                {
                    use[rc].lazy=2;
                    use[rc].sum=0;
                }
                else if(use[rc].lazy==2)
                {
                    use[rc].lazy=1;
                    use[rc].sum=r-mid;
                }
                else if(use[rc].lazy==3)
                {
                    use[rc].lazy=0;
                    use[rc].sum=r-mid-use[rc].sum;
                }
                else
                {
                    use[rc].lazy=3;
                    use[rc].sum=r-mid-use[rc].sum;
                }
            }
            use[rt].lazy=0;
        }
    }
	iv change(int rt,int l,int r,int L,int R,int z)
    {
        if(L<=l&&r<=R)
        {
            if(z==1)
            {
                use[rt].sum=r-l+1;
                use[rt].lazy=1;
            }
            else if(z==2)
            {
                use[rt].sum=0;
                use[rt].lazy=2;
            }
            else
            {
                if(use[rt].lazy==3)
                {
                    use[rt].lazy=0;
                    use[rt].sum=r-l+1-use[rt].sum;
                }
                else if(use[rt].lazy==1)
                {
                    use[rt].lazy=2;
                    use[rt].sum=0;
                }
                else if(use[rt].lazy==2)
                {
                    use[rt].lazy=1;
                    use[rt].sum=r-l+1;
                }
                else
                {
                    use[rt].sum=r-l+1-use[rt].sum;
                    use[rt].lazy=3;
                }
            }
            return;
        }
        pd(rt,l,r);
        if(mid>=L)
        {
            change(lc,l,mid,L,R,z);
           
        }
        if(mid<R)
        {
            change(rc,mid+1,r,L,R,z);
        }
        pp(rt);
    }
    ii query(int rt,int l,int r)
    {
        if(l==r)
            return lsh[l];
        pd(rt,l,r);
        if(use[lc].sum<(mid-l+1))
            return query(lc,l,mid);
        return query(rc,mid+1,r);
    }
}T;
ii read()
{
	int x=0,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()
{
	m=read();
    int maxx=0;
	for(re i=1;i<=m;i++)
	{
		ty=read();
		ul=read();
		ur=read();
        v[i].push_back(ty);
        v[i].push_back(ul);
        v[i].push_back(ur);
        maxx=max(maxx,ur);
        lsh[++cnt]=ul;
        lsh[++cnt]=ur;
        lsh[++cnt]=ul+1;
        lsh[++cnt]=ur+1;
	}
    lsh[++cnt]=1;
    maxx++;
    sort(lsh+1,lsh+cnt+1);
    cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
    maxx=lower_bound(lsh+1,lsh+cnt+1,maxx)-lsh;
    for(re i=1;i<=m;i++)
    {
        v[i][1]=lower_bound(lsh+1,lsh+cnt+1,v[i][1])-lsh;
        v[i][2]=lower_bound(lsh+1,lsh+cnt+1,v[i][2])-lsh;
    }
    int ans=0;
    for(re i=1;i<=m;i++)
    {
        ans=0;
        T.change(1,1,maxx,v[i][1],v[i][2],v[i][0]);
        ans=T.query(1,1,maxx);
        printf("%lld\n",ans);
    }
	return 0;
}

T2 赛

思路:这道题我们利用一个多指针的思想,首先先将物品分成四类,AB都喜欢,A喜欢B不喜欢,A不喜欢B喜欢,AB都不喜欢,这样我们将他们存储起来并从大到小排序,然后先假设全部选择AB都喜欢的物品,接着将指针进行移动,我在程序中标记了4个我的出错点,具体实现见代码:

#include<bits/stdc++.h>
#define int long long
#define re register int
#define ii inline int
#define iv inline void
using namespace std;
const int N=2e5+10;
const int INF=1e15;
struct CUN
{
	int v;
	friend bool operator < (CUN a,CUN b)
	{
		return a.v<b.v;
	}
}cun[N],use1[N],use2[N],use3[N],use4[N];
bool vis1[N],vis2[N];
int n,m,k,a,b;
int cnt1,cnt2,cnt3,cnt4,c1,c2,c3,c4;
int ans=INF,out;
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<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?x:(-x);
}
inline bool pd()
{
	if(cnt1>=m&&m<k)
		return 1;
	if(cnt1+cnt2<k||cnt1+cnt3<k||k*2>m+cnt1)//3
		return 1;
	return 0;
}
#undef int
int main()
{
	#define int long long
	n=read();
	m=read();
	k=read();
	for(re i=1;i<=n;i++)
		cun[i].v=read();
	a=read();
	for(re i=1;i<=a;i++)
		vis1[read()]=1;
	b=read();
	for(re i=1;i<=b;i++)
		vis2[read()]=1;
	for(re i=1;i<=n;i++)
	{
		if(vis1[i]&&vis2[i])
			use1[++cnt1].v=cun[i].v;
		else if(vis1[i])
			use2[++cnt2].v=cun[i].v;
		else if(vis2[i])
			use3[++cnt3].v=cun[i].v;
		else
			use4[++cnt4].v=cun[i].v;
	}
	if(pd())
	{
		printf("-1\n");
		return 0;
	}
	sort(use1+1,use1+cnt1+1);
	sort(use2+1,use2+cnt2+1);
	sort(use3+1,use3+cnt3+1);
	sort(use4+1,use4+cnt4+1);
	c1=min(cnt1,m);	
	if(c1<m)//1
    {
        c2=c3=max(0ll,k-cnt1);
        int now=m-c1-c2-c3;
        while(now--)
        {
            if(use2[c2+1]<use3[c3+1]&&use2[c2+1]<use4[c4+1])
            	c2++;
            else if(use3[c3+1]<use2[c2+1]&&use3[c3+1]<use4[c4+1])
            	c3++;
            else 
            	c4++;
        }
    }
	for(re i=1;i<=c1;i++)
		out+=use1[i].v;
	for(re i=1;i<=c2;i++)
		out+=use2[i].v;
	for(re i=1;i<=c3;i++)
		out+=use3[i].v;
	for(re i=1;i<=c4;i++)
		out+=use4[i].v;
	ans=min(ans,out);
	while(c1)
	{
		c1--;
		out-=use1[c1+1].v;
		int fl=0;
		if(c1+c2<k&&c2<cnt2)
		{
			++c2;
			out+=use2[c2].v;
			++fl;
		}
		if(c1+c3<k&&c3<cnt3)
		{
			++c3;
			out+=use3[c3].v;
			++fl;
		}
		if(fl==2)
		{
			if(c4==0)
				break;//2
			out-=use4[c4].v;
			--c4;	
		}
		else if(!fl)//4
		{
			if(use2[c2+1].v<use3[c3+1].v&&use2[c2+1].v<use4[c4+1].v)
			{
				++c2;
				out+=use2[c2].v;
			}
			else if(use3[c3+1].v<use2[c2+1].v&&use3[c3+1].v<use4[c4+1].v)
			{
				++c3;
				out+=use3[c3].v;
			}
			else
			{
				++c4;
				out+=use4[c4].v;
			}
		}
		ans=min(ans,out);
	}
	printf("%lld\n",ans);
	return 0;
}

T3 题

思路:

但是,我们不能暴力枚举每个状态,但是我们可以利用逆向思维反向推出合法的状态,具体实现见代码:



#include<bits/stdc++.h>
#define re register int
#define ii inline int
#define iv inline void
using namespace std;
const int N=410;
const int M=5e4+10;
struct CUN
{
	int u,v;
}use[M];
int n,m,ans;
int f[N];
bitset<N>g[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<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?x:(-x);
}
int main()
{
	n=read();
	m=read();
	for(re i=1;i<=m;i++)
	{
		use[i].u=read();
		use[i].v=read();
	}
	for(re i=1;i<=n;i++)
	{
		f[i]=1;
		g[i][i]=1;
		for(re j=m;j;j--)
		{
			int U=use[j].u,V=use[j].v;
			if(g[i][U]&&g[i][V])
			{
				f[i]=0;
				break;
			}	
			if((!g[i][U])&&(!g[i][V]))
				continue;
			g[i][U]=1;
			g[i][V]=1;
		}
	}
	for(re i=1;i<=n;i++)
	{
		if(!f[i])
			continue;
		for(re j=i+1;j<=n;j++)
		{
			if(!f[j])
				continue;
			if((g[i]&g[j])!=0)
				continue;
			++ans;
		}
	}
	printf("%d\n",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/WindZR/p/15058786.html