Week16 - 程序设计思维与实践 - 第四次CSP模拟

在这里插入图片描述
在这里插入图片描述

思路

err…送分题 ,后面 T 了四个点,注意:这道题卡了 stl 和 cin

代码实现

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int n,k,ans=0,a[maxn];
bool vis[10];
char s[20];
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%s",s);
		int sz=strlen(s);
		int sum=0;
		memset(vis,0,sizeof(vis));
		for(int i=0;i<sz;i++){
			int idx=s[i]-'0';
			if(!vis[idx]){
				vis[idx]=1;
				sum++;
			}
		}
		if(sum<k)
			ans++;
	}
	printf("%d\n",ans);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

思路

由于题意说明了圆心位于其中一个发射点上,那么枚举每一个点进行计算即可。
如有多解,输出 x 较小的点,如仍有多解,输出 y 较小的点,那么把这些点按所说的规则 sort 一下,顺序枚举即可。
ps:这里的 MAX 要设为 DBL_MAX ,习惯设 1e9 的话会有一个测试点爆掉 。

代码实现

#include <bits/stdc++.h>
using namespace std;
const int maxn=1010;
const double DIS_MAX=DBL_MAX;
const double DIS_MIN=DBL_MIN;
struct node{
	double x,y;
	bool operator<(const node &t){
		if(x!=t.x) return x<t.x;
		return y<t.y;
	}
}a[maxn];

double dis(node c,node d){
	return (c.x-d.x)*(c.x-d.x)+(c.y-d.y)*(c.y-d.y);
}

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%lf%lf",&a[i].x,&a[i].y);
	}
	sort(a,a+n);
	node ans;
	double r=DIS_MAX;
	for(int i=0;i<n;i++){
		double tmp=DIS_MIN;
		for(int j=0;j<n;j++){
			if(j!=i){
				tmp=max(tmp,dis(a[i],a[j]));
			}
		}
		if(tmp<r){
			ans.x=a[i].x;ans.y=a[i].y;r=tmp;
		}
	}
	printf("%.2lf %.2lf\n%.2lf\n",ans.x,ans.y,r);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

给定一个升序序列,要求构成一个二叉搜索树,并要求相邻两节点的 g c d gcd gcd 大于 1 1 1
由升序序列 + + + 二叉搜索树的性质大致可以看出这是一道区间 DP 题目

  • 首先 n n n 的数据范围为 700 700 700 ,则算法复杂度至少要保证小于 O ( n 3 ) O(n^3) O(n3)
  • 确定状态
    d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0] 代表以 i i i 为根, [ j , i − 1 ] [j,i-1] [j,i1] 为左子树
    d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1] 代表以 i i i 为根, [ i + 1 , j ] [i+1,j] [i+1,j] 为右子树
  • 状态转移
    • 由上述所确定的状态,对于 1 1 1 n n n 范围内的每个区间,枚举每个数作为根的情况,然后往两边扩展即可,即对于区间 [ i , j ] [i,j] [i,j],我们分别判断 i − 1 i-1 i1 j + 1 j+1 j+1 能否加入并构成二叉搜索树,最后扩展到 [ 1 , n ] [1,n] [1,n] 算法结束,状态转移方程为
      • d p [ i − 1 ] [ j ] [ 1 ] ∣ = e d g e [ i − 1 ] [ k ] dp[i-1][j][1]|=edge[i-1][k] dp[i1][j][1]=edge[i1][k]
      • d p [ j + 1 ] [ i ] [ 0 ] ∣ = e d g e [ j + 1 ] [ k ] dp[j+1][i][0]|=edge[j+1][k] dp[j+1][i][0]=edge[j+1][k]
      • 其中 e d g e [ i ] [ j ] = 1 edge[i][j]=1 edge[i][j]=1 表示点 i i i 与点 j j j g c d gcd gcd 大于 1

代码实现

#include <bits/stdc++.h>
using namespace std;
const int maxn=710;
int root,t,n,a[maxn];
bool edge[maxn][maxn],dp[maxn][maxn][2];
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(i==j) edge[i][j]=0;
				else	 edge[i][j]=(gcd(a[i],a[j])>1)?1:0;
			}
		}
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++)
			dp[i][i][0]=dp[i][i][1]=1;
		for(int j=1;j<=n;j++){
			for(int i=j;i>=1;i--){
				for(int k=i;k<=j;k++){
					if(dp[k][i][0]&&dp[k][j][1]){
						dp[i-1][j][1]|=edge[i-1][k];
						dp[j+1][i][0]|=edge[j+1][k];
					}
				}
			}
		}
		bool flag=false;
		for(int i=1;i<=n;i++){
			if(dp[i][1][0]&&dp[i][n][1]){
				printf("Yes\n");
				flag=true;
				break;
			}
		}
		if(!flag)	printf("No\n");
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值