思路
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,i−1] 为左子树
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
i−1 与
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[i−1][j][1]∣=edge[i−1][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
- 由上述所确定的状态,对于
1
1
1 到
n
n
n 范围内的每个区间,枚举每个数作为根的情况,然后往两边扩展即可,即对于区间
[
i
,
j
]
[i,j]
[i,j],我们分别判断
i
−
1
i-1
i−1 与
j
+
1
j+1
j+1 能否加入并构成二叉搜索树,最后扩展到
[
1
,
n
]
[1,n]
[1,n] 算法结束,状态转移方程为
代码实现
#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;
}