HPU暑期集训积分赛1
A. Nth power of n
单点时限: 1.0 sec
内存限制: 512 MB
求 nn 的个位数。
输入格式
多组输入,处理到文件结束。
每组数据输入一个 n。(1≤n≤109)
输出格式
输出 nn 的个位数。
思路:
简单的快速幂。
B. 复读机的力量
单点时限: 2.0 sec
内存限制: 512 MB
Codancer: “我好菜啊!”
Dicer: “我好菜啊!”
Todest: “我好菜啊!”
CaprYang: “我好菜啊!”
…
大佬们又开始装弱了,真正的菜鸡瑟瑟发抖不敢说话。
我们规定一个人是复读机当且仅当他说的每一句话都是复读前一个人说的话。
我们规定一个人是复读机当且仅当他说的每一句话都是复读前一个人说的话。
我们规定一个人是复读机当且仅当他说的每一句话都是复读前一个人说的话。
规定一个复读机的熟练度为复读数量的多少。现在给你一段聊天记录,请你找出其中的复读机们。
规定一个复读机的熟练度为复读数量的多少。现在给你一段聊天记录,请你找出其中的复读机们。
规定一个复读机的熟练度为复读数量的多少。现在给你一段聊天记录,请你找出其中的复读机们。
输入格式
输入T组,(1≤T≤10)
每组第一行输入一个正整数N,表示聊天记录的长度(1≤N≤10000)。
接下来N行,每行两个字符串,前一个字符串为姓名,后一个字符为聊天记录。
保证所有字符串长度不超过50,保证所有字符串只包含小写字母.
输出格式
如果没有复读机,输出 “Unbelievable!”(不包含引号)
否则按照熟练度从大到小输出所有的复读机,如果熟练度相同,按照字典序从小到大输出。
样例
1
4
codancer iamsovegetable
dicer iamsovegetable
todest iamsovegetable
capryang iamsovegetable
capryang
dicer
todest
思路:
利用map字典的功能来增加熟练度,并将map数据存入数组进行排序输出。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<string,string> P;
const ll MAX=1e9+10;
struct node{
string s;
int a;
}arr1[10000+10] ;
bool cmp(node x,node y){
if(x.a!=y.a)
return x.a>y.a;
return x.s<y.s;
}
int main(){
vector<P>arr;
P p;
ll a,b;
cin>>a;
string s1;
string s2;
while(a--){
cin>>b;
map<string,int>mp;
map<string,int>mp1;
for(int i=0;i<b;i++){
cin>>s1>>s2;
p.first=s1;
p.second=s2;
arr.push_back(p);//将数据存进数组
}
mp1[arr[0].first]=1;//mp1是判断他是不是复读机是的话为1
for(int i=1;i<b;i++){
if(!mp1[arr[i].first]){
if(arr[i].second==arr[i-1].second){//判断这一句与前一句是否相同
mp[arr[i].first]++;//mp来存熟练度
}
else{//如果不相同说明说这句画的人不是复读机
mp1[arr[i].first]=1;
mp[arr[i].first]=0;//令他的熟练度为0
}
}
}
int i=0;
if(mp.size()){//存入map的个数
map<string,int>::iterator it;
for(it=mp.begin();it!=mp.end();it++){
if(it->second){//复读机且熟练度不为0存入到一个数组
arr1[i].s=it->first;
arr1[i].a=it->second;
i++;//数组中个数
}
}
if(i==0){
puts("Unbelievable!");
}
else{
sort(arr1,arr1+i,cmp);//排序
for(int j=0;j<i;j++){
cout<<arr1[j].s<<endl;
}
}
}
else{
puts("Unbelievable!");
}
arr.clear();
}
return 0;
}
C. 无穷的小数
单点时限: 1.0 sec
内存限制: 512 MB
在十进制下,我们能够很轻易地判断一个小数的位数是有穷的或无穷的,但是把这个小数用二进制表示出的情况下其有穷性和无穷性就会发生改变,比如
十进制下的 0.5 ,在二进制下的值为 0.1 ;
十进制下的 0.75 ,在二进制下的值为 0.11 ;
十进制下的 0.6 ,在二进制下的值为 0.1001100......
给你一个十进制的小数,判断其在二进制表示下小数位数是否无穷。
输入格式
多组输入,处理到文件结束
每组数据输入一个六位的小数 n.(0≤n<1)
输出格式
如果在二进制下小数位数是有穷的,输出”YES”,否则输出”NO”.
样例
0.500000
0.600000
0.750000
YES NO YES
思路:
十进制小数转化为二进制小数时,可以采用乘2取整法,即将小数部分乘以2,然后取整数部分,剩下的小数部分继续乘以2,然后取整数部分,剩下的小数部分又乘以2,一直取到小数部分为零为止。
因为精度问题要将小数先化为整数,然后操作,当一个数循环到一定数目后小数部位仍然不为0,即可判断它为无限循环小数。
D. Special String
单点时限: 2.0 sec
内存限制: 512 MB
我们定义一个字符串S为Special String只要这个字符串满足下面这些条件:
1.这个串是回文的,即把这个字符串正着读和反着读相同,如abba和aca,而ba和abca则不是。
2.26个小写字母必须全部出现
3.这个串的长度为偶数。
对于给定的S,判断它是否是Special String.
输入格式
输入一个只由小写字母组成的字符串S。(1≤|S|≤105)
输出格式
如果这个字符串是Special String,输出”YE5”,否则输出”N0”
样例
aaaa
N0
abcdefghijklmnopqrstuvwxyzzyxwvutsrqponmlkjihgfedcba
YE5
思路:
根据要求逐一判断即可。注:尽量将输出内容复制粘贴到代码中,以免Wa和Pe.
E. Max Gcd
单点时限: 2.0 sec
内存限制: 512 MB
一个数组a,现在你需要删除某一项使得它们的gcd最大,求出这个最大值。
输入格式
第一行输入一个正整数n,表示数组的大小,接下来一行n个数,第i个数为ai。(2≤n≤105,1≤ai≤109)
输出格式
输出删除掉某个数以后的gcd的最大值。
样例
4
2 4 8 1
2
4
1 2 3 4
1
提示
样例一:删除第四个元素后,2,4,8的最大公因子为2。
样例二:无论删除哪一个,最大公因子都为1。
思路:
多个数求最大公约数时,前n-1个数的公约数与第n个数一起求得的公约数即为前n个数的最大公约数。
方法可用前缀后缀法,然后遍历数组,求减去某一个数后最大公约数。
代码如下:
#include <bits/stdc++.h>
using namespace std;
int q[100000+10];
int h[100000+10];
int arr[100000+10];
int main(){
int n,ans=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>arr[i];
}
q[0]=arr[0];
h[n-1]=arr[n-1];
for(int i=1;i<n;i++){
q[i]=__gcd(q[i-1],arr[i]);
h[n-i-1]=__gcd(h[n-i],arr[n-i-1]);
}
ans=max(h[1],q[n-2]);
for(int i=1;i<n-1;i++){
ans=max(ans,__gcd(q[i-1],h[i+1]));
}
cout<<ans;
return 0;
}
F. Count Prime Pairs
单点时限: 2.0 sec
内存限制: 512 MB
对于数组a,如果i≠j并且ai+aj是一个质数,那么我们就称(i,j)为质数对,计算数组中质数对的个数。
输入格式
第一行输入一个n,表示数组的长度,接下来n个整数,第i个数代表ai。
(1≤n≤100000,0≤ai≤100)
输出格式
输出数组中质数对的个数。
样例
3
1 2 3
4
提示
样例说明:a1+a2,a2+a1,a2+a3,a3+a2都为质数,总共有四对。
思路:
解题关键在于要知道将同一元素合并,然后判断任两元素之和是否为素数。提醒自己:越到最后,越不能乱,静下心来,认真思考。
代码如下:
#include <bits/stdc++.h>
using namespace std;
int arr[1000];
int arr1[100000+10];
int arr2[100000+10];
map<int,int>mp;
void su(){
for(int i=2;i<201;i++){
if(!arr[i]){
for(int j=i*2;j<201;j+=i){
arr[j]=1;
}
}
}
}
int main(){
arr[0]=1;
arr[1]=1;
su();
int a,b,sum=0,k=0,j=0;
cin>>a;
for(int i=0;i<a;i++){
scanf("%d",&b);
mp[b]++;
}
map<int,int>::iterator it1;
map<int,int>::iterator it2;
for(it1=mp.begin();it1!=mp.end();it1++){
for(it2=mp.begin();it2!=mp.end();it2++){
if(!arr[it1->first+it2->first]){
if(it1==it2)
sum+=(it1->second*(it2->second-1));
else
sum+=(it1->second*it2->second);
}
}
}
printf("%d\n",sum);
return 0;
}
G. 平行线
单点时限: 2.0 sec
内存限制: 512 MB
“大猩猩为什么不喜欢平行线?”“因为平行线没有相交”
哈哈哈哈哈哈哈哈哈
为了管理动物园不听话的大猩猩们,动物管理员Boctorio 决定去远方的ACM之城找一些平行线,当他逛到一个神奇的店铺时,他发现了一副黑色的图,上面依稀可见一些白色的点。Boctorio 询问店铺老板这幅画是什么,老板说:“天机不可泄露”。等Boctorio仔细端详了一会这幅画后,他惊讶的发现其中所蕴含的奥秘。向店铺老板道谢后,他拿着刚买的这幅画,就连忙赶回动物园。
输入格式
输入一个数 n(1≤n≤1000),表示点的个数。
接下来n行,每行两个整数 xi,yi(1≤xi,yi≤109),表示第i个点。
数据保证没有重复的点
输出格式
输出用这些点所能表示出来的平行线段的对数。(两条不同的线段重合也算为平行)
样例
6
0 0
1 0
1 1
3 1
3 3
5 4
10
思路:
使用求斜率的方法。也可用向量,下面是学长简短明了的代码。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 2000;
typedef long long ll;
int x[N],y[N];
int main(){
int n;
cin>>n;
map<pair<int,int> ,int> k;
set<pair<long long,long long> > all;
long long ans=0;
for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int dx=x[j]-x[i];
int dy=y[j]-y[i];
if(dx<0&&dy<0){
dx=-dx;
dy=-dy;
}
long long gc=__gcd(dx,dy);
dx/=gc;dy/=gc;
k[{dx,dy}]++;
all.insert({dx,dy});
}
}
for(auto v:all){
ans+=(k[v]*(k[v]-1)/2);
}
cout<<ans<<endl;
return 0;
}
H. Area of polygons
单点时限: 2.0 sec
内存限制: 512 MB
现在有a个边长为1的正方形,b个半径为1的圆,c个边长为1的等边三角形,现在你随机拿出一个图形,求这个图形面积的期望。
输入格式
第一行输入一个T,代表输入的组数。(1≤T≤100)
接下来T行,每行三个数字a,b,c(1≤a,b,c≤1000)。
输出格式
输出T行,对于每一组输入,输出面积的期望,小数点后保留三位小数。
样例
3
1 2 3
4 5 6
7 8 9
1.430
1.487
1.501
提示
圆周率为3.1415926535897