A - 夹角有多大II
这次xhd面临的问题是这样的:在一个平面内有两个点,求两个点分别和原点的连线的夹角的大小。
注:夹角的范围[0,180],两个点不会在圆心出现。
Input
输入数据的第一行是一个数据T,表示有T组数据。
每组数据有四个实数x1,y1,x2,y2分别表示两个点的坐标,这些实数的范围是[-10000,10000]。
Output
对于每组输入数据,输出夹角的大小精确到小数点后两位。
Sample
Inputcopy | Outputcopy |
---|---|
2 1 1 2 2 1 1 1 0 | 0.00 45.00 |
总结:利于高中的余弦定理,角=(pow(a,2)+pow(b,2)-pow(c,2))/2*a*b,这个角是弧度,要转化为度数
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
using namespace std;
int main()
{
int t;
while(cin>>t)
{
double x1,x2,y1,y2,a,b,c,p;
for(int i=0;i<t;i++){
cin>>x1>>y1>>x2>>y2;
a=sqrt(1.0*pow(x1,2.0)+1.0*pow(y1,2.0));//利于高中的余弦定理,角=(pow(a,2)+pow(b,2)-pow(c,2))/2*a*b,这个角是弧度,要转化为度数
b=sqrt(1.0*pow(x2,2.0)+1.0*pow(y2,2.0));
c=sqrt(1.0*pow(x1-x2,2.0)+1.0*pow(y1-y2,2.0));
p=acos((a*a*1.0+b*b*1.0-c*c*1.0)/(2.0*a*b))*180/acos(-1);//acos(-1)=pi
printf("%.2f\n",p);
//cout<<acos(-1)<<endl;
}
}
return 0;
}
B - 手机短号
大家都知道,手机号是一个11位长的数字串,同时,作为学生,还可以申请加入校园网,如果加入成功,你将另外拥有一个短号。假设所有的短号都是是 6+手机号的后5位,比如号码为13512345678的手机,对应的短号就是645678。
现在,如果给你一个11位长的手机号码,你能找出对应的短号吗?
Input
输入数据的第一行是一个N(N <= 200),表示有N个数据,接下来的N行每一行为一个11位的手机号码。
Output
输出应包括N行,每行包括一个对应的短号,输出应与输入的顺序一致。
Sample
Inputcopy | Outputcopy |
---|---|
2 13512345678 13787654321 | 645678 654321 |
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
using namespace std;
int main()
{
string s,s1="6";
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
cin>>s;
s1="6";
for(int i=6;i<11;i++)
s1+=s[i];
cout<<s1<<endl;
}
}
return 0;
}
C - 找单词
假设有x1个字母A, x2个字母B,..... x26个字母Z,同时假设字母A的价值为1,字母B的价值为2,..... 字母Z的价值为26。那么,对于给定的字母,可以找到多少价值<=50的单词呢?单词的价值就是组成一个单词的所有字母的价值之和,比如,单词ACM的价值是1+3+14=18,单词HDU的价值是8+4+21=33。(组成的单词与排列顺序无关,比如ACM与CMA认为是同一个单词)。
Input
输入首先是一个整数N,代表测试实例的个数。
然后包括N行数据,每行包括26个<=20的整数x1,x2,.....x26.
Output
对于每个测试实例,请输出能找到的总价值<=50的单词数,每个实例的输出占一行。
Sample
Inputcopy | Outputcopy |
---|---|
2 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 2 6 2 10 2 2 5 6 1 0 2 7 0 2 2 7 5 10 6 10 2 10 6 1 9 | 7 379297 |
总结:母函数的应用
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
using namespace std;
long long a[27],c1[60],c2[60],c[27],v[27];
int main()
{
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{ int a1;
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
memset(v,0,sizeof(v));
for(int j=0;j<26;j++)
{
cin>>a[j];
}
int j1=0;
for(int i=0;i<26;i++)
{
if(a[i]!=0)
{v[j1]=a[i];//数量
c[j1++]=i+1;//值
}
}
memset(c1,0,sizeof(c1));
c1[0]=1;
for(int i=0;i<j1;i++)//种类的个数
{
memset(c2,0,sizeof(c2));
for(int j=0;j*c[i]<=50&&j<=v[i];j++)//母函数
{
for(int p=0;p+j*c[i]<=50;p++)
{
c2[p+j*c[i]]+=c1[p];
}
}
memcpy(c1,c2,sizeof(c2));
}
long long sum1=0;
for(int i=1;i<=50;i++)
{
sum1+=c2[i];//所有个数相加
}
cout<<sum1<<endl;
}
}
return 0;
}
D - 简易版之最短距离
寒假的时候,ACBOY要去拜访很多朋友,恰巧他所有朋友的家都处在坐标平面的X轴上。ACBOY可以任意选择一个朋友的家开始访问,但是每次访问后他都必须回到出发点,然后才能去访问下一个朋友。
比如有4个朋友,对应的X轴坐标分别为1, 2, 3, 4。当ACBOY选择坐标为2的点做为出发点时,则他最终需要的时间为 |1-2|+|2-2|+|3-2|+|4-2| = 4。
现在给出N个朋友的坐标,那么ACBOY应该怎么走才会花费时间最少呢?
Input
输入首先是一个正整数M,表示M个测试实例。每个实例的输入有2行,首先是一个正整数N(N <= 500),表示有N个朋友,下一行是N个正整数,表示具体的坐标(所有数据均<=10000).
Output
对于每一个测试实例,请输出访问完所有朋友所花的最少时间,每个实例的输出占一行。
Sample
Inputcopy | Outputcopy |
---|---|
2 2 2 4 3 2 4 6 | 2 4 |
总结:先将数据从小到大排序,然后在选中间的基准进行计算.
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
using namespace std;
int a[600];
int main()
{
int m,n;
while(cin>>m)
{
for(int i=0;i<m;i++)
{
int p,mid;
long long s=0;
cin>>p;
memset(a,0,sizeof(a));
for(int i=0;i<p;i++)
{
cin>>a[i];
}
sort(a,a+p);//从小到大排序
mid=a[p/2];
for(int i=0;i<p;i++)//计算基准和其他点之间的距离
s+=abs(mid-a[i]);
cout<<s<<endl;
}
}
return 0;
}
E - 数塔
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:
有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
已经告诉你了,这是个DP的题目,你能AC吗?
Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample
Inputcopy | Outputcopy |
---|---|
1 5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 | 30 |
#include<iostream>
#include<string>
#include<stdlib.h>
#include<cstdio>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<vector>
typedef long long ll;
using namespace std;
int a[1000][1000],dp[1000][1000];
int main()
{ int c,n;
while(cin>>c)
{
for(int i=0;i<c;i++)
{
cin>>n;
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
cin>>a[i][j];
}
//dp[n][i]=a[n][i];
}
for(int i=1;i<=n;i++)
dp[n][i]=a[n][i];
for(int i=n-1;i>=1;i--)
{
for(int j=1;j<=i;j++)
{
dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];//简单dp应用
}
}
//输出测试
/* for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
*/
cout<<dp[1][1]<<endl;
}
}
return 0;
}
F - 核反应堆
某核反应堆有两类事件发生:
高能质点碰击核子时,质点被吸收,放出3个高能质点和1个低能质点;
低能质点碰击核子时,质点被吸收,放出2个高能质点和1个低能质点。
假定开始的时候(0微秒)只有一个高能质点射入核反应堆,每一微秒引起一个事件发生(对于一个事件,当前存在的所有质点都会撞击核子),试确定n微秒时高能质点和低能质点的数目。
Input
输入含有一些整数n(0≤n≤33),以微秒为单位,若n为-1表示处理结束。
Output
分别输出n微秒时刻高能质点和低能质点的数量,高能质点与低能质点数量之间以逗号空格分隔。每个输出占一行。
Sample
Inputcopy | Outputcopy |
---|---|
5 2 -1 | 571, 209 11, 4 提示 可以使用long long int对付GNU C++,使用__int64对付VC6 |
#include<iostream>
#include<string>
#include<stdlib.h>
#include<cstdio>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<vector>
typedef long long ll;
using namespace std;
int n;
ll s1,s2;
int main()
{
while(cin>>n)
{
if(n==-1)
break;
s1=1,s2=0;//刚开始,只有一个高质子
for(int i=1;i<=n;i++){
ll s11=0,s22=0,s111=0,s222=0;
s11=s1*3,s22=s1;//高质子撞击产生的
s111=s2*2,s222=s2;//低质子撞击产生的
s1=s111+s11,s2=s222+s22;
}
printf("%lld, %lld\n",s1,s2);
}
return 0;
}
G - A1 = ?
有如下方程:Ai = (Ai-1 + Ai+1)/2 - Ci (i = 1, 2, 3, .... n).
若给出A0, An+1, 和 C1, C2, .....Cn.
请编程计算A1 = ?
Input
输入包括多个测试实例。
对于每个实例,首先是一个正整数n,(n <= 3000); 然后是2个数a0, an+1.接下来的n行每行有一个数ci(i = 1, ....n);输入以文件结束符结束。
Output
对于每个测试实例,用一行输出所求得的a1(保留2位小数).
Sample
Inputcopy | Outputcopy |
---|---|
1 50.00 25.00 10.00 2 50.00 25.00 10.00 20.00 | 27.50 15.00 |
总结:简单数学推导,先利于公式把a1,a2,a3表示出来,然后在把a3代入a2,再把a2带入a1中,即可推出一个表达式,a1=(n*a0+an+1-(2*n*c1+2*(n-1)*c2+2*(n-2)*c3.......+2*1*cn))/(n+1);
#include<queue>
#include<string>
#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{
int n;
double a1=0,s=0,c,a0,an;
while(cin>>n)
{ s=0;
cin>>a0>>an;
for(int i=n;i>=1;i--)//先把2*n*c1...+2*1*cn求出来
{
cin>>c;
s+=2*i*c;
}
a1=(n*a0+an-s)/(n+1);//利于推导公式得到
printf("%.2f\n",a1);
}
return 0;
}
H - 剪花布条
一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?
Input
输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。
Output
输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。
Sample
Inputcopy | Outputcopy |
---|---|
abcde a3 aaaaaa aa # | 0 3 |
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
using namespace std;
int main()
{
string p,w;
while(cin>>p)
{
if(p=="#")
break;
int s=0,index=0;
cin>>w;
while(index!=-1&&index<p.size())
{
index=p.find(w,index);
if(index!=-1)
s+=1,index+=w.size();
else
break;
}
cout<<s<<endl;
}
return 0;
}
I - Box of Bricks
Little Bob likes playing with his box of bricks. He puts the bricks one upon another and builds stacks of different height. “Look, I've built a wall!”, he tells his older sister Alice. “Nah, you should make all stacks the same height. Then you would have a real wall.”, she retorts. After a little consideration, Bob sees that she is right. So he sets out to rearrange the bricks, one by one, such that all stacks are the same height afterwards. But since Bob is lazy he wants to do this with the minimum number of bricks moved. Can you help?
Input
The input consists of several data sets. Each set begins with a line containing the number n of stacks Bob has built. The next line contains n numbers, the heights hi of the n stacks. You may assume 1≤n≤50 and 1≤hi≤100.
The total number of bricks will be divisible by the number of stacks. Thus, it is always possible to rearrange the bricks such that all stacks have the same height.
The input is terminated by a set starting with n = 0. This set should not be processed.
Output
For each set, print the minimum number of bricks that have to be moved in order to make all the stacks the same height.
Output a blank line between each set.
Sample
Inputcopy | Outputcopy |
---|---|
6 5 2 4 1 7 5 0 | 5 |
总结:看似比较难,实则比较简单,只要先推一下这个过程,就会知道,原来步数=abs(每一堆砖块-平均砖块数)相加/2
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
using namespace std;
int main()
{ int a[1000];
int n,s,p1=0;
while(cin>>n)
{ s=0;
int p=0;
if(n==0)
break;
if(p1)
cout<<endl;
for(int i=0;i<n;i++)
{
cin>>a[i];
s+=a[i];
}
for(int i=0;i<n;i++)
{
p+=abs((s/n)-a[i]);
}
cout<<p/2<<endl;
p1=1;
}
return 0;
}
J - 不要62
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
Sample
Inputcopy | Outputcopy |
---|---|
1 100 0 0 | 80 |
总结:数据比较大,而且我不想搞dp,所以我就在程序运行前就先把1~1000000之间的数据算好放入数组里面这样就不会卡时间了。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
#include<ctime>
#define inf 0x3f3f3f3f
using namespace std;
long long a[1000000];
int main()
{ int n,m;
memset(a,0,sizeof(a));
a[0]=1;
for(int i=1;i<=1000000;i++)
{
string s=to_string(i);//int转字符串
if(s.find("4")==-1&&s.find("62")==-1)//find函数找匹配字符串
{
a[i]=a[i-1]+1;}//符合就在之前的基础上加一
else
a[i]=a[i-1];//不符合就等于之前的
}
while(scanf("%d %d",&n,&m)&&n*m)
{
if(n==m)//如果两个数相等,且不等于0
{
string n1=to_string(n);
if(n1.find("4")==-1&&n1.find("62")==-1)//如果这两个数不符合则输出0
cout<<1<<endl;
else
cout<<0<<endl;
}
else
cout<<a[m]-a[n]+(a[n]-a[n-1])<<endl;//a[m]-a[n]会减去n本身这个数,如果n不符合,a[m]-a[n]输出的答案是对的,如果n符合的话,答案就会少1,所以要加上(a[n]-a[n-1])防止减去n这个情况.
}
return 0;
}