zoukankan      html  css  js  c++  java
  • 2020.10.18:YC中学模拟赛

    2020.10.18:YC中学模拟赛
    (难度介于CSP-J2~CSP-S2)

    纪念品分组

    传送门

    讲解

    水题,但写sort人傻了,忘了sort是左闭右开的结构,导致数组没排完序 (分数-40)

    题意就是将N件物品2个一组,让求组数最少时,每组价值差尽量小
    具体怎么做呢?

    考试的时候,我是一开始想到的是用最小价值的物品和最大价值的物品相加,次小和次大相加,第K小的和第K大的相加,这样必定每组价值差最小

    sort(a,a+n+1);
    int l=1,r=n;
    while(l<=r){
    	l++;
    	r--;
    	ans++;
    }
    

    在这里插入图片描述

    但如果某两数之和大于价值上限怎么办?
    所以进行判断,单独取出这两个数中较大的一个,独成一组;而较小的一个参与与其他数字的合并
    在这里插入图片描述
    这是满足贪心的思想的

    代码

    #include<bits/stdc++.h>
    using namespace std;
    int mx;//每组纪念品价格之和的上限
    int n;//购来的纪念品的总件数
    int a[30100];
    int ans;
     
    int main(){
    	//freopen("souvenir.in","r",stdin);
    	//freopen("souvenir.out","w",stdout);
    	cin>>mx>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	sort(a,a+n+1);
    	int l=1,r=n;
    	while(l<=r){
    		if(a[l]+a[r]>mx){
    			r--;
    			ans++;
    		}else{//a[l]+a[r]<=mx
    			l++;
    			r--;
    			ans++;
    		}
    		
    	}
    	cout<<ans;
    	return 0;
    }
    

    开闭区间

    顺便插一句,sort一类的STL都是左闭右开的结构

    左闭右开:一种区间结构
    ( 开区间 ):区间两处的端点值取不到
    [ 闭区间 ]:区间两处的端点值可以取到

    所以,我就是忘了sort是左闭右开的那个人,然后就给下标0~n-1的数据排序,唯独没到下标n

    sort(a,a+n);
    

    城市互通

    传送门

    讲解

    就是有N个点M条边,然后看这些点边构成了多少个集合,最后-1(看需要连多少条边)就好了
    我想的是用并查集来做 (就构建集合,然后查找,比并查集模板还简单

    也没什么说的,就将每个点挂到自己的根节点上
    最后随便数一下有多少个根节点就完成

    不会并查集的同学请看看这篇文章:【并查集】一种与时间赛跑的巧妙算法
    以及学习并查集请必需掌握的链式前向星:关于路径存储的常见优化——前向星与链式前向星

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m;//N个城,M条路 
    int fa[100100];
    
    int find(int i){
    	if(i==fa[i]){//根节点 
    		return i;
    	}
    	else{
    		int x=find(fa[i]);
    		fa[i]=x;
    		return x;
    	}
    }
    int main(){
    	//freopen("city.in","r",stdin);
    	//freopen("city.out","w",stdout);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)fa[i]=i;
    	for(int i=1;i<=m;i++){
    		int x,y;
    		cin>>x>>y;//x -- y
    		
    		fa[find(x)] = find(y);
    		
    	}
    	long long ans=0;
    	for(int i=1;i<=n;i++){
    		if(find(i)!=find(i-1)){
    			fa[find(i)]=find(i-1);
    			ans++;
    		}
    	}
    	ans--;
    	cout<<ans;
    	
    	return 0;
    }
    

    游荡的奶牛

    传送门

    讲解

    就是一张NM的地图,为障碍物,求奶牛T步内从[sx,sy]到[ex,ey]的方案数

    DFS

    我最开始打了个DFS搜索,以为T<=15数据能过

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,t;
    char a[110][110];
    int sx,sy,ex,ey;
    
    int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    
    bool vis[110][110];
    
    int ans;
    
    bool in(int x,int y){
    	return 0<x&&x<=n&&0<y&&y<=m;
    }
    
    void dfs(int x,int y,int z){//[x,y],第z秒 
    	if(z>t)return;
    	if(x==ex&&y==ey){
    		ans++;
    	}
    	//cout<<x<<" "<<y<<endl;
    	for(int i=0;i<4;i++){
    		int tx=x+dir[i][0];
    		int ty=y+dir[i][1];
    		if(in(tx,ty)&&vis[tx][ty]==0&&a[tx][ty]!='*'&&z<t){
    			vis[tx][ty]=1;
    			dfs(tx,ty,z+1);
    		}
    	}
    	vis[x][y]=0;
    	return;
    }
    
    int main(){
    	//freopen("cow.in","r",stdin);
    	//freopen("cow.out","w",stdout);
    	cin>>n>>m>>t;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			cin>>a[i][j];
    		}
    	} 
    	cin>>sx>>sy>>ex>>ey;
    	dfs(sx,sy,0);
    	cout<<ans;
    	return 0;
    }
    
    

    下来大佬YJA告诉我,这样时间复杂度高达约O(4^K)(4个方向,可以走T步,最坏约为10 ^9)

    所以我们进行记忆化

    以及,我们还要考虑目前所在的点和终点间的距离(这里用曼哈顿距离进行估价,即|X1-X2|+|Y1-Y2|) 是否大于T-走过的步数
    (即:|X1-X2|+|Y1-Y2|<=t-z)
    若大于那么从起点走T次后一定无法到达终点,所以后面一切均为无用功,直接结束本次搜索(可行性剪枝)

    DP

    可以用记忆化就可能能用DP

    DP有个好处就是可以不进行可行性剪枝
    而改用三维数组,某一维记录当前步数

    在T步内,到达[i,j]方案数为上下左右除去障碍物的和
    在这里插入图片描述
    然后判断是否越界等基本操作,给f[sx,sy]赋初值=1

    f[i][j][k] 表示第k时间到达(i,j)的方案数,得到:f[x][y][k]+=f[x+dir[0][i]] [y+dir[1][i]] [k+1]

    //dir表方向变化

    代码

    DP

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,t;
    int sx,sy,ex,ey;
    char a[110][110];
    int f[110][110][110];
    int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
    bool in(int x,int y) {
    	return 0<x&&x<=n&&0<y&&y<=m;
    }
    
    int main() {
    	cin>>n>>m>>t;
    	for(int i=1; i<=n; i++) {
    		for(int j=1; j<=m; j++) {
    			cin>>a[i][j];
    		}
    	}
    	cin>>sx>>sy>>ex>>ey;
    	f[sx][sy][0]=1;
    	for(int i=1; i<=t; i++) {
    		for(int j=1; j<=n; j++) {
    			for(int k=1; k<=m; k++) {
    				if(a[j][k]!='*') {
    					for(int l=0; l<4; l++) {
    						int tx=j+dir[l][0];
    						int ty=k+dir[l][1];
    						if(in(tx,ty)&&a[tx][ty]!='*') {
    							f[j][k][i]+=f[tx][ty][i-1];
    						}
    					}
    				}
    			}
    		}
    	}
    
    	cout<<f[ex][ey][t]<<endl;
    //	for(int k=1; k<=t; k++) {
    //		for(int i=1; i<=n; i++) {
    //			for(int j=1; j<=m; j++) {
    //				cout<<f[i][j][k]<<" ";
    //			}
    //			cout<<endl;
    //		}
    //		cout<<endl;
    //	}
    	return 0;
    }
    

    理发

    传送门
    线段树,暂时不太懂
    略......
    考试的时候暴力,A了两组数据,其他超时
    在这里插入图片描述

    //A两组数据
    #include<bits/stdc++.h>
    using namespace std;
    long long n;
    long long a[10100];
    long long ans;
    int main() {
    	//freopen("haircut.in","r",stdin);
    	//freopen("haircut.out","w",stdout);
    	cin>>n;
    	for(int i=1; i<=n; i++) {
    		cin>>a[i];
    	}
    	cout<<0<<endl;
    	for(int k=1; k<n; k++) {
    		ans=0;
    		for(int i=1; i<=n; i++) {
    			for(int j=1; j<i; j++) {
    				int x=a[i];
    				int y=a[j];
    				if(x>k)x=k;
    				if(y>k)y=k;
    				if(y>x){
    					ans++;
    					//cout<<ans<<" ";
    				}
    			}
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    33.数组声明方式(var构造函数) 、检测数组类型、数组的属性(封装好的就一个length)、数组的方法
    31.this指向(写出调用链,找最近对象) this的默认绑定 隐式绑定 显示绑定(call(绑定对象) apply(绑定对象) 当括号内没放绑定对象的时候恢复默认绑定) bind
    31.
    30.函数作用域链 (GO AO 也叫词法作用域链)、 调用栈、调用栈涉及this绑定
    29.包装类(构造函数) 包装类作用及调用栈
    916. Word Subsets
    246. Strobogrammatic Number
    445. Add Two Numbers II
    2. Add Two Numbers
    341. Flatten Nested List Iterator
  • 原文地址:https://www.cnblogs.com/pqh-/p/13872280.html
Copyright © 2011-2022 走看看