雅礼集训2017day10乱写

t1

我们假设每个位置被(d[i])个人选择了,并设(s[k]=(sumlimits_{i=1}^{k}d[i])-k)

找出最小的(k),可以证明如果从(k+1)开始讨论,所有精灵都不用跨过((k,k+1))寻找对手

然后就是贪心问题了,遍历到一个位置,把将要与其决斗的精灵插入(set)

然后再(set)中找第一个大于等于当前力量值的精灵

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=5e5+10,inf=0x3f3f3f3f;
	int n,k,minn,sum,ret;
	int head[N],cnt;
	struct point
	{
		int nxt,to;
		point(){}
		point(const int &nxt,const int &to):nxt(nxt),to(to){}
	}a[N<<1];
	int p[N],b[N],c[N],d[N]; 
	set<int> s;
	set<int>::iterator it;
	inline void link(int x,int y)
	{
		a[++cnt]=(point){head[x],y};head[x]=cnt;
	}
	inline void main()
	{
		n=read();minn=inf;
		for(int i=1;i<=n;++i) p[i]=read(),++d[p[i]],link(p[i],i);
		for(int i=1;i<=n;++i) b[i]=read();
		for(int i=1;i<=n;++i) c[i]=read();
		for(int i=1;i<=n;++i)
		{
			sum+=d[i];
			if(minn>sum-i) minn=sum-i,k=i;
		}
		for(int i=1;i<=n;++i)
		{
			if(++k>n) k=1;
			for(int e=head[k];e;e=a[e].nxt)
			{
				int t=a[e].to;
				s.insert(c[t]);
			}
			if(b[k]>*--s.end()) s.erase(s.begin());
			else it=s.lower_bound(b[k]),s.erase(it),++ret;
		}
		printf("%d
",ret);
	}
}
signed main()
{
	red::main();
	return 0;
}

t2

求严格上升子序列,我们可以把整个序列赋值一边翻转然后插在开头

(4 3 1 2 2 1 3 4)

求出这个序列的最长严格上升子序列长度和方案数,然后将方案数乘以(2^{n-maxlen-1})

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=5e5+10,mod=1e9+7,inf=0x3f3f3f3f; 
	int n;
	int a[N],b[N];
	int c[N],num;
	int f[N],g[N],len[N];
	struct node
	{
		int x,y;
	}ans[N<<2];
	inline node merge(node a,node b)
	{
		if(a.x==b.x) return(node){a.x,(a.y+b.y)%mod};
		return a.x<b.x?b:a;
	}
	inline void update(int pos,int l,int r,int p,node k)
	{
		if(l==r)
		{
			ans[p]=merge(ans[p],k);
			return;
		}
		if(pos<=mid) update(pos,l,mid,ls(p),k);
		if(pos>mid) update(pos,mid+1,r,rs(p),k);
		ans[p]=merge(ans[ls(p)],ans[rs(p)]);
	}
	inline node query(int pos,int l,int r,int p)
	{
		if(r<=pos) return ans[p];
		if(mid<pos) return merge(query(pos,l,mid,ls(p)),query(pos,mid+1,r,rs(p)));
		return query(pos,l,mid,ls(p));
	}
	inline void main()
	{
		n=read();
		for(int i=1;i<=n;++i) a[i]=b[i]=read(),c[++num]=a[i];
		sort(c+1,c+n+1);
		num=unique(c+1,c+num+1)-c-1;
		reverse(a+1,a+n+1);
		for(int i=1;i<=n;++i) a[i+n]=b[i];
		for(int i=1;i<=n*2;++i)
		{
			a[i]=lower_bound(c+1,c+num+1,a[i])-c+1;
			node t=query(a[i]-1,1,n+1,1);
			if(t.x==0) t=(node){1,1};
			else ++t.x;
			update(a[i],1,n+1,1,t);
		}
		node t=query(n+1,1,n+1,1);
		printf("%d ",t.x);
		for(int i=1;i<=n-t.x-1;++i) t.y=t.y*2%mod;
		if(t.x==n) t.y=1;
		printf("%d ",t.y);
	}
}
signed main()
{
	red::main();
	return 0;
}

t3

我们可以把苍蝇拍套在矩阵里,然后枚举左下角就可以枚举到全部位置

先用(bitset)把哪些位置有苍蝇标记出来,然后把苍蝇拍可以覆盖到的位置标记为(1)

然后枚举(x)轴和左下角,判断是否会拍到苍蝇

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=510,M=1e5+10,mod=1e9+7,inf=0x3f3f3f3f; 
	int n,m,k,top,minx=inf,miny=inf,maxx=-inf,maxy=-inf;
	int ret;
	struct node
	{
		int x,y;
	}p[M],nfly,a,b;
	bitset<N> pfly[N],fly[N],now;
	double st[N];
	bool ans[N][N];
	inline void main()
	{
		n=read(),m=read(),k=read();
		for(int i=1;i<=k;++i)
			nfly.x=read(),nfly.y=read(),fly[nfly.x].set(nfly.y);
		k=read();
		for(int i=1;i<=k;++i)
		{
			p[i].x=read(),p[i].y=read();
			minx=min(minx,p[i].x);
			miny=min(miny,p[i].y);
			maxx=max(maxx,p[i].x);
			maxy=max(maxy,p[i].y);
		}
		maxx-=minx,maxy-=miny;
		for(int i=1;i<=k;++i)
			p[i].x-=minx,p[i].y-=miny,pfly[p[i].x].set(p[i].y);
		for(int x=0;x<=maxx;++x)//把苍蝇拍的覆盖到的点标记为1 
		{
			top=0;
			for(int i=1;i<=k;++i)
			{
				a=p[i],b=p[i==k?1:i+1];
				if(a.y>b.y) swap(a,b);
				if((a.x<x&&b.x<x)||(a.x>x&&b.x>x)||(a.x==x&&b.x>x)||(b.x==x&&a.x>x)) continue;
				if(a.x==x&&b.x==x)
				{
					for(int y=a.y+1;y<=b.y-1;++y) pfly[x].set(y);
					continue;
				}
				double k=1.0*(b.y-a.y)/(b.x-a.x);
				st[++top]=k*(x-a.x)+a.y;
			}
			sort(st+1,st+top+1);
			for(int y=0,flag=0,i=1;y<=maxy;++y)
			{
				while(i<=top&&st[i]<y) ++i,flag^=1;
				if(flag||(i<=top&&st[i]==y)) pfly[x].set(y);
			}
		}
		for(int i=0;i<=maxx;++i)
		{
			for(int y=0;y<=m-maxy;++y)
			{
				now=pfly[i]<<y;
				for(int x=0;x<=n-maxx;++x)
				{
					if(!ans[x][y]&&(now&fly[x+i]).any())//在哪些点下手会拍到苍蝇 
						ans[x][y]=1;
				}
			}
		}
		for(int x=0;x<=n-maxx;++x)
		{
			for(int y=0;y<=m-maxy;++y)
			{
				ret+=!ans[x][y];
			}
		}
		printf("%d
",ret);
	}
}
signed main()
{
	red::main();
	return 0;
}
原文地址:https://www.cnblogs.com/knife-rose/p/12807167.html