您的位置:首页 > 其它

新生选拔赛一

2014-11-13 13:13 375 查看
A 传送门:noj 2066

简单的求和输出,只是和为0时输出字符串。

不过比赛过程中出现了一个没想到的问题,大家输出数字时注意到输出回车了,可是却忘了字符串时的回车,大家有经验之后就不会犯这样的问题了

/******************************************************
* File Name:   2066.cpp
* Author:      kojimai
* Create Time: 2014年11月13日 星期四 13时09分38秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
int keng,a,b,c,d;
scanf("%d",&keng);
while(keng--)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
int ans = a + b + c + d;
if(ans == 0)
printf("sidajiekong\n");
else
printf("%d\n",ans);
}
return 0;
}


B 传送门:noj 2063

题意:从一个数组中找出三个数,使得它们能够构成一个三角形,且构成的三角形的周长最大。

贪心题,给数组排序之后,从最大数开始枚举,每一次都选择当前能选到的和最大的三个数,然后判断这三个数是否能构成三角形,若能则这个三角形的周长就是答案了。若直到最后都找不到三个能构成三角形的数则输出-1即可

/******************************************************
* File Name:   2063.cpp
* Author:      kojimai
* Create Time: 2014年11月13日 星期四 13时17分45秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 23
int a[FFF];

int main()
{
int keng;
scanf("%d",&keng);
while(keng--)
{
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%d",&a[i]);
sort(a,a+n); // 这是一个系统函数,实现从小到大的排序
int ans = -1;//还没有找到可行解时给答案赋值为-1
for(int i = n-1; i > 1 && ans == -1 ;i--)
{
for(int j = i - 1;j > 0 && ans == -1;j--)
{
for(int k = j - 1;k >= 0 && ans == -1;k--)
{
if(a[j] + a[k] > a[i])
{
ans = a[j] + a[k] + a[i];
}
}
}
}
//找到可行解时ans==-1的条件不再满足因此退出循环
printf("%d\n",ans);
}
return 0;
}


C 传送门:noj 2070

题意:第一秒有一只兔子,这只兔子每一秒都会生出一只兔子,然后新出生的兔子在出生后的第4秒开始每秒也会生一只兔子,问指定时间有多少只兔子

斐波那契数列的变形题,这里我用递推的方式写

因为最多只问到第55秒,所以我们可以直接先求出这55秒的结果,然后按输入直接输出

处理方法:

①暴力递推:

第一只兔子从第二秒开始每一秒都会生一只兔子,

后来新出生的兔子从出生的第4秒开始直到最后每秒都会生一只兔子,

于是我们可以计算每一秒有多少兔子新出生,并处理出这些新出生的兔子在之后的时间内生的新兔子,最后求和即可

/******************************************************
* File Name:   2070.cpp
* Author:      kojimai
* Create Time: 2014年11月13日 星期四 13时29分50秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 55
int a[FFF];//存每一秒的兔子总和
int b[FFF];//存每一秒新生出的兔子数量
void init()
{
memset(b,0,sizeof(b));
a[1] = 1;
for(int i = 2; i <= 55;i++)
b[i] = 1;//第一只兔子在每一秒都会新生出一只兔子
for(int i = 2; i <= 55;i++)
{
a[i] = a[i-1] + b[i];
for(int j = i + 3; j <= 55;j++)
{
b[j] += b[i];//这一秒出生的兔子在之后的时间内生的兔子,加到那一秒新出生的兔子数量上
}
}
return;
}

int main()
{
init();
int keng;
scanf("%d",&keng);
while(keng--)
{
int n;
scanf("%d",&n);
printf("%d\n",a
);
}
return 0;
}


② 斐波那契数列版:

不强求大家理解,看看吧 递推公式 a[i] = a[i-1]+a[i-3]

/******************************************************
* File Name:   2070_2.cpp
* Author:      kojimai
* Create Time: 2014年11月13日 星期四 13时45分54秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 55
int a[FFF];
void init()
{
a[1] = 1;
a[2] = 2;
a[3] = 3;
a[4] = 4;
for(int i = 5;i <= 55;i++)
a[i] = a[i-1] + a[i-3];
}
int main()
{
init();
int keng,n;
cin>>keng;
while(keng--)
{
cin>>n;
cout<<a
<<endl;
}
return 0;
}


D 传送门:noj 2071

题意:就是题目所说,把数字码转换成HDB3码,

出题人的恶趣味,就是模拟处理,考验大家的代码水平。处理方法:

首先,从头到尾扫一边,把所以的1分别变为+1,1。

然后再扫一边,找出所有的4连零,把对应位置变成+V,-V。(正负号根据前面最靠近的的1正负号定)

最后再扫一边,需要一个标识符号,表示当前的符号需不需要变化。假如有两个相邻的V中间有偶数个1,则改为B00V,符号依情况而定,且标识符取反,奇数则不变,然后根据标识符继续向后扫

/******************************************************
* File Name:   hdb3.cpp
* Author:      kojimai
* Create Time: 2014年10月30日 星期四 13时03分29秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 105
int a[FFF];
void print(int x)
{
switch(x)//根据对应的数输出对应的符号
{
case 0:cout<<0;return;
case 1:cout<<"+1";return;
case 2:cout<<"+V";return;
case 3:cout<<"+B";return;
case -1:cout<<"-1";return;
case -2:cout<<"-V";return;
case -3:cout<<"-B";return;
}
}
int main()
{
int n;
cin>>n;
for(int i = 1;i <= n;i++)
cin>>a[i];
bool flag = false; //记录下一个1的符号 false(即0) 表示 下一个1为 -1  true(即1)  表示下一个1为 +1
for(int i = 1;i <= n;i++)
{
if(a[i] == 1)
{
if(flag)
{
flag = false;
}
else
{
a[i] = -1;
flag = true;
}
}
}
int cnt = 0;//记录当前访问到的连0的个数
for(int i = 1;i <= n;i++)
{
if(a[i] == 0)//遇到0 cnt值加1
{
cnt++;
if(cnt == 4)//遇到四连零则变化
{
if(flag)//依据最靠近的1的符号确定V的符号
a[i] = 2;//2表示+V
else
a[i] = -2;//-2表示-V
cnt = 0;//清零
}
}
else if(a[i] == 1)
{
cnt = 0;
flag = true;//表示下一次遇到4连零时需要改为+V
}
else
{
flag = false;//下一次遇到4连零时改为-V
cnt = 0;
}
}
//	for(int i = 1;i <= n;i++)
//		cout<<a[i]<<" ";cout<<endl;
bool turn = false,first = true;
cnt = 0;
for(int i = 1;i <= n;i++)
{
if(a[i] == -2 || a[i] == 2)
{
if(first)//第一个4连零不需要改为B00V
{
first = false;
cnt = 0;
continue;
}
if(turn)//根据反型符号进行变化
{
a[i] = -a[i];
}
if(cnt % 2 == 0)//cnt表示相邻的两个V之间1的个数
{
//为偶数时
if(a[i] == 2)//当前V为+V时 这一段000+V 要变成 -B00-V
{
a[i-3] = -3;//-3表示-B
a[i] = -2;//-2表示-V
}
else//V为-V时
{
a[i-3] = 3;//+B
a[i] = 2;//+V
}
turn = !turn;//标识符
}
cnt = 0;
}
else if(a[i] == 1 || a[i] == -1)
{
if(turn)//遇到1需要反型
a[i] = -a[i];
cnt++;
}
}
for(int i = 1;i <= n;i++)
{
print(a[i]);
if(i<n)
cout<<' ';
else
cout<<endl;//c++的回车符
}
return 0;
}


E 传送门:noj 2068

题意:超出给定的数组可以找多少不同的连续子串,使得子串中的任意两个数不能相等。(这里的不同只需要满足位置不同就好)

简单来想就是找两个点(l,r),使得这两个点范围内的所有数都不想等,找出这样的点对有多少个

我们可以这样做,从左往右扫,记录一个left表示到位置i为止,最小的left使得left+1到i-1位置上所有的数都不相同

然后新加来第i个数,

①如果这个数和left+1到i-1的数都不相同,那么以i为有端点,以left+1到i为左端点的所有子串都可以,因此统计的答案加上 i-left

②如果这个数和left+1到i-1范围内的某个数相同了,那么就需要更新left使得left满足①的要求,把left更新成第i个数最后一次出现的位置即可。(原因大家思考一下)

/******************************************************
* File Name:   2068.cpp
* Author:      kojimai
* Create Time: 2014年11月13日 星期四 14时09分48秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 1000005
int a[FFF],last[FFF];//last数组记录每一个数最后一次出现的位置,0表示没有出现过
int main()
{
int keng;
scanf("%d",&keng);
while(keng--)
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
memset(last,0,sizeof(last));
int ans = 0,left = 0;
for(int i = 1;i <= n;i++)
{
if(last[a[i]] > left)//a[i]和left+1~i-1中的某个数重复了,则需要更新left值
left = last[a[i]];
ans += i - left;
last[a[i]] = i;
}
cout<<ans<<endl;
}
return 0;
}


F 传送门:noj 2069

题意:判断给定的三个数的素因子集合是否相同

首先求出这三个数的最大公约数,然后每个数都进行如下操作

①和最大公约数求新的公约数,并除以它

②新的公约数为1或者,数本身变为1,则停止,否则重复①操作

到最后如果三个数都变为1,则说明这三个数素因子集合相同

/******************************************************
* File Name:   2069.cpp
* Author:      kojimai
* Create Time: 2014年11月13日 星期四 14时24分46秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;

int gcd(int x,int y)//辗转相除法求最大公约数,不懂请自行查找介绍
{
int b;
while(y)
{
b = y;
y = x % y;
x = b;
}
return b;
}

int solve(int x,int t)//这个三个数跟原来的公约数不断求新的公约数并除以新的公约数使得数不断缩小,直到新的公约数为1或者原来的数变为1
{
while(x>1)
{
int y = gcd(x,t);
if(y==1)
break;
x = x / y;
}
return x;
}

int main()
{
int keng;
scanf("%d",&keng);
while(keng--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int t = gcd(a,b);
t = gcd(t,c);//求出三个数的最大公约数
a = solve(a/t,t);
b = solve(b/t,t);
c = solve(c/t,t);
if(a == 1 && b == 1 && c == 1)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: