问题 A: 打印方阵
题目描述
下面这样的方阵很有规律,称为蛇形方阵。例如33的:
1 2 3
6 5 4
7 8 9
现在给定边长,输出相应的蛇形方阵。
输入
1个整数n,表示要输出nn的蛇形方阵,1<=n <=100。
输出
n行,每行n个整数,空格隔开。
样例输入 Copy
4
样例输出 Copy
1 2 3 4
8 7 6 5
9 10 11 12
16 15 14 13
思路:
第一行从左到右增大,下一行从右向左增大,只需要定义一个变量k,k = 0时,从左向右增大,一行数填完之后标记k = 1,继续循环即可
int a[105][105];
int n,k,tot;
int main()
{
cin >> n;
memset(a,0,sizeof(a));
k = 0,tot = 1;
for(int i=0;i<n;i++)
{
if(k == 0)
{
for(int j=0;j<n;j++)
{
a[i][j] = tot++;
k = 1;
}
}
else
{
for(int j=n-1;j>=0;j--)
{
a[i][j] = tot++;
k = 0;
}
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
return 0;
}
问题 B: 分数减法
题目描述
这样的分式运算我们都会。请编程计算两个分数相减的结果。
输入
第一行2个整数a和b,表示一个分数a/b,1<=a 第二行2个整数c和d,表示一个分数c/d,1<=c
输出
2个整数,表示结果。
提示:运算结果分式要约分。
样例输入 Copy
4 7
1 3
样例输出 Copy
5 21
思路:
先计算b、d的最小公倍数,把分母通分,然后计算新的分子分母的最大公约数,对结果进行约分。要考虑如果最后分子是分母倍数的情况
ll a,b,c,d,x,y,z;
int main ()
{
cin >> a >> b;
cin >> c >> d;
z = gcd(b,d);//最大公约数
y = b*d/z;//最小公倍数
x = a*(y/b)-c*(y/d);
if(x/y == 1) printf("1\n");
else
{
if(x%y == 0) printf("%d\n",x/y);
else
{
z = gcd(x,y);
x = x/z;
y = y/z;
printf("%d %d\n",x,y);
}
}
return 0;
}
问题 E: 可表示的数
题目描述
有N个整数从左到右排成一行,如果某个数等于它前面的2个数的和,就称这个数是可以表示的数。问给定的数列里有多少个数是可以表示的数。
输入
第一行1个整数N,表示数列有多少个整数。1<=N<=10000。
第二行N个正整数,每个正整数不超过10000。
输出
一个整数,有多少可表示的数。
样例输入 Copy
8
5 2 2 3 4 8 7 16
样例输出 Copy
3
提示
4=2+2;8=5+3; 7=3+4
思路:
三层循环会超时,所以考虑用两层循环解决。把两个数相加之后的和用数组标记为1,当标记数组为1时,则结果++。这里要注意每次在最前面进行if的判断,这样可以保证是这个数的前面两个数的和
int n,ans;
int a[10005],vis[20005];
int main()
{
cin >> n;
for(int i=0;i<n;i++)
{
cin >> a[i];
if(vis[a[i]] == 1) ans++;//保证和在后面
//如果把这一行判断单独拿出来,则无法保证先后顺序
for(int j=0;j<i;j++)
{
vis[a[i]+a[j]] = 1;
}
}
cout << ans << endl;
return 0;
}
问题 F: 叠罗汉
题目描述
农场的N头奶牛喜欢玩叠罗汉游戏,就是几头奶牛1头奶牛接着1头奶牛的站成一柱子形状。不过奶牛的力量不一样,用数值Ci表示第i头奶牛它的上面最多可以站多少头奶牛,问这些奶牛最少可以站成几个柱子形状。
输入
第一行1个整数N,表示有多少头奶牛。1<=N<=1000。
第二行N个正整数Ci,表示这些奶牛的力量。0<=Ci<=1000。
输出
一个整数,表示最少成几个“罗汉”。
样例输入 Copy
5
0 2 1 2 2
样例输出 Copy
2
提示
可以第1、第3、第2头奶牛从上向下叠罗汉; 第4、第5头奶牛叠罗汉。
思路:
有点贪心的思想,让力量大的放在底部。把每一个力量的数量记录一下,遍历力量,如果存在比当前力量大的并且满足这个数大于等于上面已经叠好的,那么这一组罗汉的个数就可以加一,同时记录这个力量的数组减一
int n,x,ans,cnt;
int vis[1005];
int main()
{
cin >> n;
for(int i=0;i<n;i++)
{
cin >> x;
vis[x]++;
}
for(int i=0;i<=1000;i++)
{
while(vis[i] > 0)//存在这个力量
{
ans++;
cnt = 0;
for(int j=i;j<=1000;j++)
//从这个力量往上,判断有没有比当前力量更大的,如果有,就可以放在下面
{
while(vis[j] > 0 && j >= cnt)
{
vis[j]--;//用过一个之后就减少
cnt++;//在最下面放了一个就+1
}
}
}
}
cout << ans << endl;
return 0;
}
问题 H: 掰手腕
题目描述
编程集训,好累人!
课间,有N个人闹着要掰手腕比赛,时间有限,只进行K场对弈。
每个人最多参加两场对弈,最少参加零场对弈。
每个人都有一个与其他人都不相同的等级(用一个正整数来表示)。
在对弈中,等级高的人在裁判的右边,等级低的人在裁判的左边。
每一个人最多只能在左边和右边各一次。
为了增加比赛的可观度,观众希望K场对弈中双方的等级差的总和最小。
比如有7个选手,他们的等级分别是30,17,26,41,19,38,18,要进行3场比赛。最好的安排是Player 2 vs Player 7, Player 7 vs Player 5 , Player 6 vs Player 4,此时等级差的总和等于(18 - 17) + (19 - 18) + (41 - 38) = 5达到最小。
输入
第一行两个正整数N,K;
接下来有N行,第i行表示第i+1个人等级。
输出
在第一行输出最小的等级差的总和。
样例输入 Copy
7 3
30
17
26
41
19
38
18
样例输出 Copy
5
提示
在90%的数据中,1 ≤ N ≤ 3000;
在100%的数据中,1 ≤ N ≤ 100000;
保证所有输入数据中等级的值小于10^8,1 ≤ K ≤ N-1 。
思路:
首先对原数据排序,把每两个数之间的差值保存下来,对差值再排序,将前k个加和即可
int n,k,ans,cnt;
int a[maxn],b[2*maxn];
int main()
{
cin >> n >> k;
for(int i=0;i<n;i++) cin >> a[i];
sort(a,a+n);
for(int i=0;i<n-1;i++)
b[cnt++] = a[i+1]-a[i];
sort(b,b+cnt);
for(int i=0;i<k;i++)
ans += b[i];
printf("%d\n",ans);
return 0;
}
问题 I: 踢石头
题目描述
编程集训,真累人!
课间,某君在操场上沿着笔直的跑道从左往右走着、散步休息……
看到有N个排成一直线的小石头,于是他无聊的踢了起来:
在他遇到第“奇数”块石头时,他会将其往前面踢,能踢多远在输入中会给出,而遇到第“偶数”个石头时不进行处理(不踢:略过)。当有多个石头在同一位置时,则先处理“射程”(踢下,石头往前移的距离)最短的石头。
然后他就这么一直往前走,边走边踢,直到前面已经没有任何石头时,这时候计算该群与出发点的距离。
输入
第一行一个正整数N (0
输出
前面没石头时,离出发点的距离
样例输入 Copy
【样例1】
2
1 5
2 4
【样例2】
2
1 5
6 6
样例输出 Copy
【样例1】
11
【样例2】
12
提示
样例1解析
一开始的时候遇到的是第一个石头(1,5),他的坐标是1,然后往前踢了5个单位之后,坐标变成(6,5) 随后继续往前走,开始遇到第二个石头(2,4),忽略过。 然后继续往前走,遇到了第三个石头(6,5),即原第一个石头,但是它此时坐标为6。往前踢了5个单位之后,坐标变成(11,5), 继续往前走,一直走到坐标11时,遇到第四个石头(11,5),忽略。 前面已经没有石头了,因此此时离坐标原点的距离为11。
在90%的数据中,1 ≤ N ≤ 3000;
在100%的数据中,1 ≤ N ≤ 100000;
保证所有输入数据中等级的值小于10^8,1 ≤ K ≤ N-1 。
思路:
我们可以运用优先队列解决上述问题,先将每个石头的位置及其能够扔的距离封装成一个结构体。优先队列的优先级即可。利用一个bool变量来控制奇偶,奇数时处理,偶数时不处理。最后的一个石头的坐标即是能扔的最远的距离
ll n;
struct node
{
ll p;
ll d;
friend bool operator<(node a,node b)
{
if(a.p == b.p) return a.d > b.d;
return a.p > b.p;
}
};
int main()
{
cin >> n;
node a;
priority_queue<node> q;
for(int i=0;i<n;i++)
{
cin >> a.p >> a.d;
q.push(a);
}
bool temp = true;//切换奇偶
while(!q.empty())
{
a = q.top(); q.pop();
if(temp)
{
a.p += a.d;
q.push(a);//踢出去的石头放回队列
}
temp = !temp;
}
cout << a.p << endl;
return 0;
}