A 崔哥的信仰
时间限制:1000ms内存限制:65536KB
总通过人数:175 总提交人数:176
评测记录:{A182701}
解题思路:
将每个物品的参数储存到数组a中,下标由1到n;
再将数组a用sort函数排序,在输出a[n]和a[n-1]即可。
参考代码:
#include
#include
#include
#include
using namespace std;
int main(){
int n;
scanf("%d",&n);
long long a[20000];
for(int i=1; i<=n; i++){
scanf("%lld",&a[i]);
}
sort(a+1, a+1+n);
printf("%lld %lld\n",a[n],a[n-1]);
B 王助教掷骰子
时间限制:1000ms内存限制:65536KB
总通过人数:22 总提交人数:147
评测记录:{B184164}
解题思路:
这道题我使用了递推的方法:
将骰子的六个面分成两类:初始面+它的对面,记为P面 和 其余的四个侧面,记为Q面;
易知第n次初始面和它的对面朝上的概率相等; 其余四个侧面朝上的概率相等;
用P(n)表示第n次滚动后P面朝上的概率,Q(n)表示第n次滚动后Q面朝上的概率。
只有当第n-1次滚动后Q面朝上,才可能下一次滚动后P面朝上,并且概率为1/2;
|
|
于是有:
P(n) = Q(n-1)/2;--------------[1]
又因为Q(n) + P(n) = 1;
故:
Q(n) = 1 - P(n);---------------[2]
[1] [2]式构成了一个递推关系,易知P(1) = 0,Q(1) = 1,便能递推出第k次滚动后的P和Q,接着P/2便得到初识面和tade对面朝上的概率,Q/4便得到其余四个侧面朝上的概率。
但是,由于k最大为2^31-1,约等于20亿,也就是最多要进行几十亿次计算,肯定会超时,所以还需要优化算法。
此时注意到答案只需要保留两位小数(以百分数的形式),而P(14)/2 = 0.166687; Q(14)/4=0.1666565; P(15)/2=0.166672; Q(15)/4=0.166664....之后P(n)/2和Q(n)/4的前四位已经稳定,所以继续求下去结果不会改变,所以程序最多只需要递推14次即可;
此外,由[1][2]可得Q(n) = 1 - Q(n-1)/2; 即得到了Q(n)的递推公式,由高中知识可得Q(n)的通项公式:
,便可直接求出P和Q,不需要担心超时的问题,强无敌!!
参考代码:
法一:
#include
#include
#include
#include
using namespace std;
int main(){
double p, q, mid;
double ans[8];
long k;//每组数据两个整数i与k,表示初始面i,滚动k次。
int i,j;
while(scanf("%d%ld",&i,&k)==2){
if(k==0){
for(int m=1; m<=6; m++){
if(m!=i) ans[m]=0.0;
else ans[m]= 100.0;
}
}
else{
p = 0.0; q = 1.0;
for(j=2; j<=k&&j<=14; j++){//j表示第几次滚动
mid = q;
q = p + mid / 2.0;
p = mid / 2.0;
}
if(i==1||i==6){
ans[1] = ans[6] = p / 2.0 * 100;
ans[2] = ans[3] = ans[4] = ans[5] = q / 4.0* 100;
}
else if(i==2||i==5){
ans[2] = ans[5] = p / 2.0* 100;
ans[1] = ans[3] = ans[4] = ans[6] = q / 4.0* 100;
}
else{
ans[3] = ans[4] = p / 2.0* 100;
ans[1] = ans[2] = ans[5] = ans[6] = q / 4.0* 100;
}
}
printf("%.2f%% %.2f%% %.2f%% %.2f%% %.2f%% %.2f%%\n",ans[1],ans[2],ans[3],ans[4],ans[5],ans[6]);
}
}
法二:
#include
#include
int main(){
double p, q, mid;
double ans[8];
long k;//每组数据两个整数i与k,表示初始面i,滚动k次。
int i,j;
while(scanf("%d%ld",&i,&k)==2){
if(k==0){
for(int m=1; m<=6; m++){
if(m!=i) ans[m]=0.0;
else ans[m]= 100.0;
}
}
else{
q = (1.0/3.0)*pow(-0.5,k-1)+2.0/3.0;
p=1-q;
if(i==1||i==6){
ans[1] = ans[6] = p / 2.0 * 100;
ans[2] = ans[3] = ans[4] = ans[5] = q / 4.0* 100;
}
else if(i==2||i==5){
ans[2] = ans[5] = p / 2.0* 100;
ans[1] = ans[3] = ans[4] = ans[6] = q / 4.0* 100;
}
else{
ans[3] = ans[4] = p / 2.0* 100;
ans[1] = ans[2] = ans[5] = ans[6] = q / 4.0* 100;
}
}
printf("%.2f%% %.2f%% %.2f%% %.2f%% %.2f%% %.2f%%\n",ans[1],ans[2],ans[3],ans[4],ans[5],ans[6]);
}
}
C DH分组员
时间限制:1000ms内存限制:65536KB
总通过人数:21 总提交人数:153
评测记录:{C183564}
解题思路:
首先对a1~an求和,得到sum,再分两种情况讨论:
由于sum <= 10^10, 超过了int的范围,故使用long long 声明sum
1. 若sum除不尽K,说明无法平分
直接输出-1;
2. 否则,说明可以平分
ave = sum / K; //求得均分后每组的人数
由于最后每组的人数都得是ave,于是只要人数不是ave的组都要被合并或拆分;
于是,从第一组开始,不断与后一组的合并,且每合并一次操作次数++,直到所得的人数和sum可以除尽ave,这时再把sum均分,操作次数+=(sum/ave-1)即可;(这里我仍然使用了变量sum,而没有定义新的变量)
之后再从下一组开始重复上述操作,直到n组全部完成分配;
输出ans(操作次数)。
参考代码:
#include
int main(){
int N,K,i,j,l,ans=0;
int a[110000];
long long sum=0,ave;
scanf("%d%d",&N,&K);
for(i=1; i<=N; i++){
scanf("%d",&a[i]);
sum+=a[i];
}
if(sum%K!=0) printf("-1\n");
else{
ave = sum / K;
l=1;
while(l<=N){
for(i=l,sum=a[i]; sum%ave!=0; i++,ans++){
sum+=a[i+1];
}
ans+=((sum/ave)-1);
l=i+1;
}
printf("%d\n",ans);
}
}
D 混乱的辈分关系
时间限制:1000ms内存限制:65536KB
总通过人数:3 总提交人数:46
评测记录:{D188332}
解题思路:
这个题我主要使用了数组,冒泡算法和深搜。
整个程序大致分为以下四步:
1.按照题目要求输入----input()
a) ajiaob[][]二维数组储存叫爸爸关系,值为1说明a叫过b爸爸;
b) father数组储存爸爸值,同时用father2数组备份其数据,因为之后的排序会打乱下标;
c) weizhi数组储存每个人所在的位置
d) old数组储存每个人的年龄,同时用old2数组备份
2.对所有人排序,找出爸爸值最大的几个人---max()
a) 使用冒泡算法将所有人按照爸爸值降序排列,注意交换顺序时要将两个人的所有信息(father值,old值,weizhi值)全部交换
b) 找出和第一名爸爸值相同的所有人,为备份最高的候选人,并储存总候选人数。
3.找出辈分最大的那个人---zhangzhe()
a) 使用compare()函数比较辈分,第一个人与第二个人比较辈分,大的那一个再与下一个人比较,以此类推,找到辈分最大的那个人
b) 输出这个人的位置
c) compare()函数:
i. 使用dfs(p,q)函数判断p是否叫过q或q的子孙爸爸;
ii. 记录dfs(p,q)和dfs(q,p)的值,同时注意在每次使用dfs()函数前,都要对visit数组清零
iii. 若dfs(p,q) == 1且dfs(q,p)==0,返回q
若dfs(p,q) == 0且dfs(q,p)==1,返回p
若二者都不满足,用年龄判断辈分,返回辈分较大的那个
d) dfs()函数:
深搜,看爸爸关系能否从p推到q
将a叫过b爸爸想象成由a指向b的一根箭头
搜索是否由p能走到q
int dfs(int p, int q){
int i;
visit[p] = 1;
if(ajiaob[p][q]==1) return 1;
for(i=1; i<=n; i++){
if(visit[i]==0&&ajiaob[p][i]==1){
if(dfs(i,q)==1) return 1;
}
}
return 0;
}
4.按顺序输出这个人的所有儿子---erzi()
a) 通过ajiaob这个数组找到这个人的所有儿子
b) 使用冒泡算法,以爸爸值为第一关键字,年龄为第二关键字,对所有儿子降序排序
由于之前的排序已经将下标打乱,这次的排序就需要使用备份的数据
c) 按顺序输出所有儿子的位置
反思:
1. 听说这道题使用类会比较简单,但是我还不会,只能用数组来储存所有信息,非常麻烦
2. 数组太多容易搞混,必须要明确每个数组储存了什么信息,有怎样的变化
3. 这次使用的模块化编程效果不错,容易查错,但必须区分清每个函数的作用
参考代码:
#include
#include
using namespace std;
int n,m;
int father[11000],father2[11000];
int old[110],old2[110];
int weizhi[110];//[]内表示当前的位置,值表示原来的位置
int ajiaob[110][110];//值为1代表 a叫过b爸爸
int visit[110];
void input(void);//按要求输入
void max();//找到爸爸值最大的几个人的位置,储存到maxfather数组中,并返回共有几个人
void zhangzhe(int);//返回找到的辈分最大的那个人的位置
int compare(int p,int q);//比较两个爸爸值相同的人的辈分,返回辈分比较大的那个人的位置
int dfs(int p, int q);//判断p是否叫过q或q的某个子孙(儿子、孙子或曾孙等)爸爸,是返回1,否返回0
void erzi(int);//输入长者的位置(是一开始输入的位置),找到并按顺序输出所有的儿子
int main(){
input();
max();
}
void input(void){
int a,b;
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++){
scanf("%d%d",&a,&b);
if(a!=b){
father[a]--;
father[b]++;
ajiaob[a][b] = 1;
}
}
for(int i=1; i<=n; i++){
scanf("%d",&old[i]);
old2[i] = old[i];
father2[i] = father[i];
weizhi[i] = i;
}
}
void max(){
int i,j,mid;
for(i=1; i<=n-1; i++){
for(j=n; j>=i+1; j--){
if(father[j]>father[j-1]){
mid = father[j];
father[j] = father[j-1];
father[j-1] = mid;
mid = weizhi[j];
weizhi[j] = weizhi[j-1];
weizhi[j-1] = mid;
mid = old[j];
old[j] = old[j-1];
old[j-1] = mid;
}
}
}
for(i=2,j=2; i<=n; i++){
if(father[i]==father[1]){
j++;
}
}
j--;
zhangzhe(j);
}
void zhangzhe(int sum){
int j = weizhi[1];
for(int i=2; i<=sum; i++){
j = compare(j,weizhi[i]);
}
printf("%d\n",j);
erzi(j);
}
int compare(int p, int q){
int t,v,i;
for(i=1; i<=100; i++){
visit[i] = 0;
}
t = dfs(p,q);
for(i=1; i<=100; i++){
visit[i] = 0;
}
v = dfs(q,p);
if(t==1&&v==0) return q;
else if(t==0&&v==1) return p;
else if(old2[p]>old2[q]) return p;
else if(old2[q]>old2[p]) return q;
}
int dfs(int p, int q){
int i;
visit[p] = 1;
if(ajiaob[p][q]==1) return 1;
for(i=1; i<=n; i++){
if(visit[i]==0&&ajiaob[p][i]==1){
if(dfs(i,q)==1) return 1;
}
}
return 0;
}
void erzi(int p){
int weizhi2[110];
int father3[11000];
int old3[110];
int sum = 1,mid;
int i, j;
for(i=1; i<=n; i++){//先找到所有儿子
if(ajiaob[i][p]==1){
weizhi2[sum] = i;
father3[sum] = father2[i];
old3[sum] = old2[i];
sum++;
}
}
sum--;
for(i=1; i<=sum-1; i++){//给儿子们排序
for(j=sum; j>=i+1; j--){
if(father3[j]>father3[j-1]){
mid = father3[j];
father3[j] = father3[j-1];
father3[j-1] = mid;
mid = weizhi2[j];
weizhi2[j] = weizhi2[j-1];
weizhi2[j-1] = mid;
mid = old3[j];
old3[j] = old3[j-1];
old3[j-1] = mid;
}
else if(father3[j]==father3[j-1]){
if(old3[j]>old3[j-1]){
mid = father3[j];
father3[j] = father3[j-1];
father3[j-1] = mid;
mid = weizhi2[j];
weizhi2[j] = weizhi2[j-1];
weizhi2[j-1] = mid;
mid = old3[j];
old3[j] = old3[j-1];
old3[j-1] = mid;
}
}
}
}
for(i=1; i<=sum; i++){//按顺序输出所有儿子
printf("%d ",weizhi2[i]);
}
}
704

被折叠的 条评论
为什么被折叠?



