zoukankan      html  css  js  c++  java
  • [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
    ",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!

  • 相关阅读:
    2022 开年计划
    阿里云,华为云产品使用汇总
    git 连接gitlab
    golang 学习汇总
    mongodb分片集群的搭建总结
    2021 年终 总结,随想
    vue请求RSA加密
    sockjsnode/info请求失败
    rules校验
    [转]SPRINGBOOT启动流程及其原理
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/9474611.html
Copyright © 2011-2022 走看看