A - TT数鸭子
描述:
输入输出及样例:
输入:
输入第一行包含两个数n,k,表示鸭子的个数和题目要求的k。
接下来一行有n个数,
a
i
a_i
ai,每个数表示鸭子被TT映射之后的值。
输出:
输出一行,一个数,表示满足题目描述的鸭子的个数。
样例:
输入:
6 5
123456789 9876543210 233 666 1 114514
输出:
4
思想:
long long大约可以保存19位,所以没有必要用字符串读入,直接开long long 整型数保存数字。num[i]代表i在一个数字中是否出现过,如果没出现过,该数字中不同的数字个数weinum加一,并将num[i]标记为1。判断比较weinum输出结果。while循环内通过不断模10得到各个位置的数字。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k;
int ans;
int num[10];//表示0-9的数字有没有出现过;
long long a;
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++){
scanf("%lld",&a);
//memset(num,0,sizeof(num));
for(int i=0;i<10;i++)num[i]=0;
int weinum=0;
while(a>0){
int wei=a%10;
if(num[wei]==0){
num[wei]=1;
weinum++;
}
a=a/10;
}
if(weinum<k)ans++;
}
printf("%d\n",ans);
return 0;
}
B - ZJM要抵御宇宙射线
描述:
输入输出及样例:
输入:
输入 第一行一个正整数N,表示宇宙射线发射点的个数
接下来N行,每行两个整数X,Y,表示宇宙射线发射点的位置
输出:
输出包括两行:
第一行输出保护罩的中心坐标x,y 用空格隔开;
第二行输出保护罩半径的平方;
(所有输出保留两位小数,如有多解,输出x较小的点,如扔有多解,输入y较小的点),无行末空格。
样例:
输入:
5
0 0
0 1
1 0
0 -1
-1 0
输出:
0.00 0.00
1.00
思想:
看一下数据组成n不超过1000,O(n^2)就是1e6,可以试试。
直接暴力枚举圆心r,计算其包围所有质点的最小半径。
第二层遍历半径,获取最大距离以便圆能够覆盖所有点。
按条件比较半径,x坐标以及y坐标。
这里注意是输出半径的平方,不是半径orz,读题不仔细,没有看清楚输入输出要求。
代码:
#include<iostream>
using namespace std;
#define ll long long
int n;
ll nowr,ansx,ansy;
ll ansr=1e12;
struct node{
ll x,y;
}nodes[1010];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld%lld",&nodes[i].x,&nodes[i].y);
for(int i=0; i<n; i++){
nowr=0;
for(int j=0; j<n; j++)
if(i!=j){
ll dis=(nodes[i].x-nodes[j].x)*(nodes[i].x-nodes[j].x)
+(nodes[i].y-nodes[j].y)*(nodes[i].y-nodes[j].y);
nowr=max(nowr,dis);
}
if(ansr>nowr){
ansr=nowr;
ansx=nodes[i].x;
ansy=nodes[i].y;
}
else if(ansr==nowr){
if(ansx>nodes[i].x || (ansx==nodes[i].x&&ansy>nodes[i].y)){
ansx=nodes[i].x;
ansy=nodes[i].y;
}
}
}
printf("%lld.00 %lld.00\n%lld.00",ansx,ansy,ansr);
return 0;
}
/*
5
0 0
0 1
1 0
0 -1
-1 0
*/
C - 宇宙狗的危机
描述:
在瑞神大战宇宙射线中我们了解到了宇宙狗的厉害之处,虽然宇宙狗凶神恶煞,但是宇宙狗有一个很可爱的女朋友。最近,他的女朋友得到了一些数,同时,她还很喜欢树,所以她打算把得到的数拼成一颗树。
这一天,她快拼完了,同时她和好友相约假期出去玩。贪吃的宇宙狗不小心把树的树枝都吃掉了。所以恐惧包围了宇宙狗,他现在要恢复整棵树。
但是它只知道这棵树是一颗二叉搜索树,同时任意树边相连的两个节点的gcd(greatest common divisor)都超过1。 但是宇宙狗只会发射宇宙射线,他来请求你的帮助,问你能否帮他解决这个问题。
补充知识:
GCD:最大公约数,两个或多个整数共有约数中最大的一个 ,例如8和6的最大公约数是2。
一个简短的用辗转相除法求gcd的例子:
int gcd(int a,int b){return b == 0 ? a : gcd(b,a%b);}
输入输出及样例:
输入:
输入第一行一个t,表示数据组数。对于每组数据,第一行输入一个n,表示数的个数。接下来一行有n个数
a
i
a_i
ai,输入保证是升序的。
输出:
每组数据输出一行,如果能够造出来满足题目描述的树,输出Yes,否则输出No。无行末空格。
样例:
样例1:
16
3 6 9 18 36 108
Yes
样例2:
22
7 17
9
4 8 10 12 15 18 33 44 81
No
Yes
样例1可构造如下图:
思想:
动态规划区间型:
令right_tree[ i ][ j ]表示区间[ i+1,j ]是否是一个二叉搜索树(其本身可以作为一个右子树);
令left_tree[i][j]表示区间[i][j-1]是否可以作为一个二叉搜索树(其本身可以作为一个左子树);
dp[i][j]表示数a[i]和数a[j]最大公因数大于1;
如果left_tree[i][root] && right_tree[root][j],则root可以作为桥梁连接[i][root-1]和[root+1][j];
同时,如果dp[i-1][root]==1,则root与i-1之间的边合法,则整个[i][j]可以作为一个右子树;按照定义的right_tree[i-1][j]置1;左子树同理;
题目中的求最大公因数用辗转相除法;{return b == 0 ? a : gcd(b,a%b);}
代码:
#include<bits/stdc++.h>
using namespace std;
int t,n;
int a[710];
int left_tree[710][710];
int right_tree[710][710];
int dp[710][710];//满足gcd要求;
int gcd(int a,int b)
{return b == 0 ? a : gcd(b,a%b);}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
memset(dp, 0, sizeof(dp));
memset(left_tree, 0, sizeof(left_tree));
memset(right_tree, 0, sizeof(right_tree));
int flag=0;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){//所有满足边相连要求的点的对
for(int j=i;j<=n;j++){
if(gcd(a[i],a[j])>1)
dp[i][j]=1,dp[j][i]=1;
}
}
for(int i=1;i<=n;i++){
left_tree[i][i]=1;
right_tree[i][i]=1;
}
for(int i=n;i>0;i--){
for(int j=i;j<=n;j++){
for(int root=i;root<=j;root++)
{//遍历根节点
if(left_tree[i][root] && right_tree[root][j])
{//左右都可成树;
if(i==1 && j==n){//所有数均可成树;
flag=1;
break;
}
if(dp[i-1][root]) right_tree[i-1][j]=1;
if(dp[j+1][root]) left_tree[i][j+1]=1;
}
}
if(flag) break;
}
if(flag) break;
}
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}