[20180814]校内模拟赛

T1 覆盖(cover)


问题描述

二维平面上有n个点,第i个点为\((x_i,y_i)\)。你可以选出若干个点, 选出的每个点可以覆盖以这个点为原点的

坐标系的四个象限之一内的点和这个象限边界上的点。求至少需要选出几个点才能覆盖所有点。


输入格式

多组数据,第一行一个正整数T。

每组数据第一行一个正整数n。

接下来n行,每行两个整数\(x_i,y_i\)


输出格式

对于每组数组输出一行一个整数,表示答案。


样例

样例输入

1
4
5 0
-5 0
0 5
0 -5

样例输出

2

Solution

如果恰好有点位于所有点的左下角(或右上角或右下角或左下角),答案为1;

否则,答案为2;


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
#define MN 100005
#define inf (1e9+5)
int T,n,x[MN],y[MN],Xmax,Xmin,Ymax,Ymin;
bool flag;
int main(){
	freopen("cover.in","r",stdin);
	freopen("cover.out","w",stdout);
	T=read();register int i;
	while(T--){
		n=read();
		Xmax=Ymax=-inf;
		Xmin=Ymin=inf;flag=0;
		for(i=1;i<=n;i++){
			x[i]=read();y[i]=read();
			Xmax=std::max(Xmax,x[i]);
			Xmin=std::min(Xmin,x[i]);
			Ymax=std::max(Ymax,y[i]);
			Ymin=std::min(Ymin,y[i]);
		}
		for(i=1;i<=n;i++){
			if((x[i]==Xmax||x[i]==Xmin)&&(y[i]==Ymax||y[i]==Ymin)){
				flag=1;break;
			}
		}
		puts(flag==1?"1":"2");
	}
	return 0;
}





T2 匹配(match)


问题描述

你有n个数字对\((a_i,b_i)\)和m个数字\(c_i\),数字对i和数字j能匹配的条件是\(c_j\)\(a_i\)+\(b_i\)

匹配后会产生max(\(c_j\)-\(b_i\),0)的权值。一个数字对最多与一个数字匹配,一个数字最多与一个数字对匹配。

你需要在最大化匹配对数的情况下最小化权值和。


输入格式

第一行两个正整数n,m。

第二行n个正整数,表示\(a_i\)

第三行n个正整数,表示\(b_i\)

第四行m个正整数,表示\(c_i\)


输出格式

输出两个整数,分别表示最大匹配对数和最小的权值和。


样例

样例输入

5 5
2 5 3 6 2
6 2 1 3 2
6 8 7 8 6

样例输出

3 8

数据范围

对于 100%的数据,n,m ≤ 2*10^5 ,ai ,bi ,ci ≤ 10^9 。


Solution

考虑贪心,显然如果\(c_i < c_j\),那么\(c_i\)就会比\(c_j\)更优。

所以如果我们知道最大匹配对数p的话,就只要取前p小的\(c_i\)进行匹配

预处理出每个\(c_i\)对应的可以匹配的区间,然后从小到大模拟一遍,即可得到最大匹配数

最后一步,依然是贪心,优先考虑\(c_i\)值较大的,把可取的所有b值中最大的匹配给它

可以证明这样是最优的。

要找最大值,开个priority_queue就行了

复杂度O(nlogn)


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
#define MN 200005
int n,m,a[MN],b[MN],c[MN],id[MN],last[MN];
bool cmp(const int&x,const int&y){
	return a[x]+b[x]>a[y]+b[y];
}
std::priority_queue<int> Q;
long long ans=0;
int main(){
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	n=read(),m=read();
	register int i,j;
	for(i=1;i<=n;i++) a[i]=read();
	for(i=1;i<=n;i++) b[i]=read();
	for(i=1;i<=m;i++) c[i]=read();
	for(i=1;i<=n;i++) id[i]=i;
	std::sort(c+1,c+m+1);
	std::sort(id+1,id+n+1,cmp);
	int len=std::min(n,m);
	for(i=len,j=0;i;i--){
		while(a[id[j+1]]+b[id[j+1]]>=c[i]&&j+1<=n) j++;
		last[i]=j;
	}
	int pos=MN,num=0;
	for(i=1;i<=len;i++){
		if(last[i]==0||pos==1) break;
		pos=std::min(pos-1,last[i]);num++;
	}
	len=num;num=1;
	printf("%d ",len);
	for(i=len;i;i--){
		for(;num<=last[i];) Q.push(b[id[num++]]);
		ans+=std::max(c[i]-Q.top(),0);Q.pop();
	}
	printf("%lld\n",ans);
	return 0;
}





T3 裁剪(tailor)


问题描述

你有一个字符串A,但你不喜欢串A,你喜欢的是串B。

于是你想要删掉A中的若干个字符,使得B在A中的出现次数尽量多。在这里,B在A中的出现次数定义为最多能选出多少个A的不相交子串满足这些子串都等于B。

你需要对每个x求出从A中删去x个字符后B的最大出现次数。


输入格式

第一行一个小写字符串A。

第二行一个小写字符串B。


输出格式

一行∣A∣+1个整数,第i个表示x=i-1时的答案。∣A∣表示字符串A的长度。


样例

样例输入

axbaxxb
ab

样例输出

0 1 1 2 1 1 0 0 

Solution

\(f_{i,j}\)表示前i个字符删了j个的答案,分情况转移:

  1. 删除第i个字符,且对答案没有影响:\(f_{i-1,j}\)—>\(f_{i,j+1}\)
  2. 保留第i个字符,但对答案没有影响:\(f_{i-1,j}\)—>\(f_{i,j}\)
  3. 对答案有影响:预处理第i个字符后至少删几个才能形成一个B串,得到\(t_i\),那么

\[f_{i,j}+1—>f_{i+len(b)+t_i,j+t_i} \]


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MN 2005
char a[MN],b[505];
int la,lb;
int f[MN][MN],t[MN];
inline void rw(int &a,int b){if(a<b) a=b;}
int main(){
	freopen("tailor.in","r",stdin);
	freopen("tailor.out","w",stdout);
	register int i,j,k;
	scanf("%s%s",a+1,b+1);
	la=strlen(a+1);lb=strlen(b+1);
	for(i=1;i<=la;i++){
		for(j=i,k=0;j<=la&&k<lb;j++) a[j]==b[k+1]?k++:t[i]++;
		k!=lb?t[i]=MN+1:0;
	}
	memset(f,128,sizeof f);f[0][0]=0;
	for(i=0;i<la;i++)for(j=0;j<=la;j++)
		if(f[i][j]>=0){
			rw(f[i+1][j],f[i][j]);
			rw(f[i+1][j+1],f[i][j]);
			t[i+1]<MN?rw(f[i+lb+t[i+1]][j+t[i+1]],f[i][j]+1),0:0;
		}
	for(i=0;i<=la;i++) printf("%d ",f[la][i]);
	puts("");
	return 0;
}






Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2018-08-14 14:54  PaperCloud  阅读(282)  评论(0编辑  收藏  举报