CSUFT2018年春季第二次个人赛 题解
- A : A - A Very Hard Question
- B : Linear Algebra Test
- D : Dice Game
- E : The Architect Omar
- F : Building Numbers
- H : Eyad and Math
- I : Move Between Numbers
- K : Malek and Summer Semester
A : A Very Hard Question
并不想写题解,看懂题意就完事了
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--) {
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",x*100/(100+y));
}
return 0;
}
B : Linear Algebra Test
题目大意:就是给n个矩阵的行列情况,问哪些矩阵可以相乘。
解题思路:没别的,要加快查找的速度,所以使用map存储,找的很快。
#include <bits/stdc++.h>
using namespace std;
map<long ,long> row,col;
long long fun(long long a,long long b) {
return a*b;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
row.clear();
col.clear();
int n;
scanf("%d",&n);
int u,v;
for(int i=0;i<n;i++) {
scanf("%d%d",&u,&v);
if(row.count(u)==0) row[u]=1;
else row[u]++;
if(col.count(v)==0) col[v]=1;
else col[v]++;
}
long long sum=0;
for(map<long,long>::iterator i=row.begin(); i!=row.end(); i++) {
if(col.count(i->first)!=0)
sum += fun(i->second,col[i->first]);
}
printf("%lld\n",sum);
}
return 0;
}
D : Dice Game
题目大意:给出骰子的六面,骰子没滚动一次加上朝上面的数字,问加到n,最少需要滚动多少步,每次骰子从1滚动,滚动只能有90°。
题目解析:小于12的点数可以直接搞定,大于12的点数,每次都1->5->6就可以最快,找找规律就好了。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
const int maxn=100005;
int a[25]={0,1,1,1,1,1,
2,3,2,2,2,
2,3,3,3,3,
3,4,4,4,4,4,4};
int main()
{
// freopen("in.txt","r",stdin);
int T,n;
scanf("%d",&T);
int yu,bei;
while(T--)
{
int ans=0;
scanf("%d",&n);
if(n==1)
cout<<-1<<endl;
else if(n<=11)
cout<<a[n]<<endl;
else if(n>11)
{
while(n>11){
n-=11;
ans+=2;
}
if(n==7)
ans-=1;
ans+=a[n];
cout<<ans<<endl;
}
}
}
E : The Architect Omar
题目大意:题目给定了四个字符串,要在其他的字符串中找出来,并且只会出现在头几个字符。
题目解析:所以很简单的。匹配字符串,统计数量,按题目要求分类就好了。
#include <bits/stdc++.h>
using namespace std;
char str[3][10] = {"living","kitchen","bed"};
char s[55];
bool fun1(char *s1,char *s2) {
int len = strlen(s2);
if(strlen(s1)<len) return false;
for(int i=0;i<len;i++) {
if(s1[i]!=s2[i])
return false;
}
return true;
}
int fun(){
if(fun1(s,str[0]))
return 1;
if(fun1(s,str[1]))
return 2;
if(fun1(s,str[2]))
return 3;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--) {
int n;
scanf("%d",&n);
int ans[3]={0,0,0};
for(int i=0;i<n;i++) {
cin>>s;
switch(fun()) {
case 1:ans[0]++;
break;
case 2:ans[1]++;
break;
case 3:ans[2]++;
break;
}
}
int minn = ans[0];
if(ans[1]<minn)
minn = ans[1];
if(ans[2]/2<minn)
minn = ans[2]/2;
printf("%d\n",minn);
}
return 0;
}
F : Building Numbers
题目大意:给T组输入,每组第一行给两个数字n和q,接下来是一行n个数字,,然后是q行的询问,每行询问两个数字,l和r,代表范围。n行数字的每一个数字可以有两种方式从1递增产生,如8可以1->2->4->8;如11可以1->2->4->8->9->10->11,但是有更快的方式1->2->4->5->10->11,只有五步就可以完成11的递增。所以找到给定的范围[l,r]内的数字最小的递增次数和。
解题思路:
第一的问题:对单个数字而言怎么才是最小的递增次数。答案是多乘2,所以对这个数字,我们尽可能的去除以2,不能除以2就要加以,倒过来考虑是最好的,这是因为在递增过程中,最接近目标数字的时候乘以二的增大效果是最明显的,所以格外的需要乘以二。因此倒过来考虑,n不断的除以二,不能除2的时候才减去1。这样子的接近速度明显是最优秀的。
第二个问题,这个问题的解非常的需要时间,所以一般的解法会超时,因为不断地选择区间,导致白白的多求了很多遍重复的解。所以我们使用前缀和的技巧。比如对下列数:
a
1
,
a
2
,
.
.
.
,
a
i
,
.
.
.
,
a
n
a_1,a_2,...,a_i,...,a_n
a1,a2,...,ai,...,an;我们假如用,计算出每一个
a
i
a_i
ai的解
d
i
d_i
di ,那么我们定义
s
i
s_i
si为
∑
k
=
1
i
d
i
\sum_{k=1}^{i}{d_i}
∑k=1idi那么任意的区间段的和我们都可以用s的差来表示,如[l,r],等于
s
r
−
s
l
−
1
s_r-s_{l-1}
sr−sl−1;这样子只需要
O
(
n
)
O(n)
O(n)的时间复杂度就可以找到任意区间段的和。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
long long a[maxn],ans[maxn];
long long fun(long long a) {
int ans=0;
while(a>1) {
if(a%2==0) a/=2;
else a--;
ans++;
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--) {
int n ,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%lld",&a[i]);
}
ans[0] = 0;
for(int i=1;i<=n;i++)
ans[i]=fun(a[i])+ans[i-1];
int r,l;
for(int i=0;i<k;i++) {
scanf("%d%d",&r,&l);
cout<<ans[l]-ans[r-1]<<endl;
}
}
return 0;
}
H : Eyad and Math
题目大意:比较
a
b
a^b
ab和
c
d
c^d
cd谁比较大。
解题思路:直接算大小是不可能的,运算超时,所以两边同时取对数。再比较。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
int a,b,c,d;
while(T--) {
scanf("%d%d%d%d",&a,&b,&c,&d);
double aa = log(a),cc = log(c);
aa = aa*b;
cc = cc*d;
if(aa<cc)
printf("<\n");
else if(aa>cc)
printf(">\n");
}
return 0;
}
K : Malek and Summer Semester
题目大意: 给一排数字大于50的是达标的,求达标率有没有达到给定的值。
解题思路:水货。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--) {
int n;
double m;
scanf("%d%lf",&n,&m);
int sum=0,temp;
for(int i=0;i<n;i++) {
scanf("%d",&temp);
if(temp>=50)
sum++;
}
if((double)sum/n >m){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
return 0;
}
其他的题目没有改。