TT数鸭子
题目大意
给定n,k以及n个数,判断n个数中有多少个数的数位中不同数字个数小于k。
输入
输入第一行包含两个数n,k,表示鸭子的个数和题目要求的k。
接下来一行有n个数,,每个数表示鸭子被TT映射之后的值。
输出
输出一行,一个数,表示满足题目描述的鸭子的个数。
数据范围
数据点 | |||
基本思路
逐位读入数字,利用数组或set统计即可。
完整代码
#include<iostream>
#include<string>
using namespace std;
int n, k, res;
int isok(const string &num)
{
if(k>10) return 1;
int nbr[11]={0};
int c=0;
for(int i=0, l=num.length();i<l;i++)
{
if(!nbr[num[i]-'0'])
{
c++;
nbr[num[i]-'0']=1;
}
}
if(c<k) return 1;
return 0;
}
int main ()
{
ios::sync_with_stdio(false);
cin>>n>>k;
string tmp;
for(int i=0;i<n;i++)
{
cin>>tmp;
res += isok(tmp);
}
cout<<res<<endl;
return 0;
}
ZJM要抵御宇宙射线
题目大意
二维平面上,给定N个点(每个点x,y均为整数),需要以其中一个点位圆心画圆,圆要把所有点都包括进来。求半径最小的圆的圆心坐标以及半径的平方。
输入
第一行一个正整数N,表示宇宙射线发射点的个数。
接下来N行,每行两个整数X,Y,表示宇宙射线发射点的位置。
输出
输出包括两行:
第一行输出保护罩的中心坐标x,y 用空格隔开;
第二行输出保护罩半径的平方(所有输出保留两位小数,如有多解,输出x较小的点,如扔有多解,输入y较小的点)。
无行末空格。
数据范围
数据点 | |||
基本思路
暴力穷举所有情况即可。即穷举所有的圆心位置,对于每个圆心计算与其他所有点的距离,从而找到最小半径。
完整代码
#include<iostream>
using namespace std;
int N;
long long x[1005], y[1005];
long long resX, resY;
long long res;
long long getRes(int i)
{
long long r=-1;
long long d;
for(int j=0;j<N;j++)
{
if(j == i) continue;
d = (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
if(d>r) r=d;
}
return r;
}
int main ()
{
cin>>N;
for(int i=0;i<N;i++) cin>>x[i]>>y[i];
resX=x[0];
resY=y[0];
res=getRes(0);
for(int i=1;i<N;i++)
{
long long r=getRes(i);
if(r<res)
{
res=r;
resX = x[i];
resY = y[i];
}
else if(r == res)
{
if(x[i]<resX)
{
resX = x[i];
resY = y[i];
}
else if(x[i] == resX && y[i] < resY)
{
resX = x[i];
resY = y[i];
}
}
}
cout<<resX<<".00 "<<resY<<".00"<<endl;
cout<<res<<".00"<<endl;
return 0;
}
宇宙狗的危机
题目大意
给定n个升序排列的数,这n个数是升序排列的,问这n个数是否可以构成一棵二叉搜索树,并且树种每条边的两端点最大公约数都大于1。
求最大公约数的代码如下:
int gcd(int a,int b){return b == 0 ? a : gcd(b,a%b);}
输入
输入第一行一个t,表示数据组数。 对于每组数据,第一行输入一个n,表示数的个数 接下来一行有n个数,输入保证是升序的。
输出
每组数据输出一行,如果能够造出来满足题目描述的树,输出Yes,否则输出No。无行末空格。
数据范围
数据点 | |||
基本思路
这是一个区间dp问题,状态及转移如下所示:
状态 | :a[l+1]-a[r]是否可以作为l的右子树;:a[l]-a[r-1]是否可以作为r的左子树 |
初始化 | |
转移过程 |
维护两个数组lreach和rreach,lreach[l][r]表示ldp[l][r]是否被更新过,rreach[l][r]表示rdp[l][r]是否被更新过。
利用lreach和ldp可以实现lquery(l,r)函数,该函数返回a[l+1]-a[r]是否可以作为l的右子树,实现方法如下所示:
bool lquery(int l, int r) //闭区间
{
if(!lreach[l][r])
{
lreach[l][r] = true;
for(int i=l+1;i<=r;i++)
{
if(rquery(l+1,i) && lquery(i, r) && gcd(a[i], a[l]) > 1)
{
ldp[l][r] = true;
break;
}
}
}
return ldp[l][r];
}
同理可以实现rquery(l,r),利用这两个函数便可以判断一个n个数是否可以组成二叉搜索树,方式如下:
bool query()
{
for(int i=0;i<n;i++)
{
if(rquery(0, i) && lquery(i, n-1)) return true;
}
return false;
}
在规定的时间内想到区间dp并找到合适的状态和转移可能难度不小,使用记忆化的方法尝试构造二叉搜索树也是一个较好的选择,可以拿到50-60分。
完整代码(区间dp)
#include<iostream>
using namespace std;
int a[750];
bool ldp[750][750], rdp[750][750];
bool lreach[750][750], rreach[750][750];
int t, n;
int gcd(long long a, long long b){return b == 0 ? a : gcd(b,a%b);}
bool rquery(int l, int r);
bool lquery(int l, int r) //闭区间
{
if(!lreach[l][r])
{
lreach[l][r] = true;
for(int i=l+1;i<=r;i++)
{
if(rquery(l+1,i) && lquery(i, r) && gcd(a[i], a[l]) > 1)
{
ldp[l][r] = true;
break;
}
}
}
return ldp[l][r];
}
bool rquery(int l, int r) //闭区间
{
if(!rreach[l][r])
{
rreach[l][r] = true;
for(int i=l;i<=r-1;i++)
{
if(rquery(l,i) && lquery(i, r-1) && gcd(a[i], a[r]) > 1)
{
rdp[l][r] = true;
break;
}
}
}
return rdp[l][r];
}
bool query()
{
for(int i=0;i<n;i++)
{
if(rquery(0, i) && lquery(i, n-1)) return true;
}
return false;
}
int main ()
{
cin>>t;
for(int k=0;k<t;k++)
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
lreach[i][j] = ldp[i][j] = rreach[i][j] = rdp[i][j] = false;
}
}
for(int i=0;i<n;i++)
{
lreach[i][i] = ldp[i][i] = rreach[i][i] = rdp[i][i] = true;
}
if(query()) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
完整代码(构造 + 记忆化数组)
#include<iostream>
using namespace std;
long long a[800];
int gcd(long long a, long long b){return b == 0 ? a : gcd(b,a%b);}
int n;
bool ok[500][500][500];
bool get[500][500][500];
bool isok(int root, int l, int r)
{
if(get[l][r][root])
{
return ok[l][r][root];
}
bool lf=false, rf=false;
if(root == l) lf=true;
else
{
for(int i=l;i<root;i++)
{
if(isok(i,l,root) && gcd(a[i], a[root]) > 1)
{
lf=true;
break;
}
}
}
if(root == r-1) rf=true;
else
{
for(int i=root+1;i<r;i++)
{
if(isok(i,root+1,r) && gcd(a[i], a[root]) > 1)
{
rf=true;
break;
}
}
}
get[l][r][root] = true;
ok[l][r][root] = rf && lf;
if(rf && lf)
{
return true;
}
else return false;
}
int main ()
{
int t;
cin>>t;
for(int i=0;i<t;i++)
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
for(int k=0;k<=n;k++)
{
get[i][j][k] = ok[i][j][k] = false;
}
}
}
bool flag = false;
for(int i=0;i<n;i++)
{
if(isok(i, 0, n))
{
flag=true;
break;
}
}
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}