天天快乐编程2020年OI集训队 训练11题解
上次发现大家对简单题还是掌握不牢固,这次还是一些简单题,也就是比赛中第一第二题给你们练练。大家如果不是很忙的话注意一下赛后的补题,即使你是入门级的同学,提高级的题目也是可以尝试的。
1.6019: 金币
NOIP2015 普及组T1
这个题目k仅有10,000,比较小,可以直接一重循环
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i, n, x = 1, t = 1, sum = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
sum += t;
//到x了,下次要多一个币
if (i == x)
{
t++;
x += t;
}
}
printf("%d\n", sum);
return 0;
}
模拟的方法有麻烦的,有简单的,建议写简单的方法
这个题目存在一个通项公式的写法吗,前面是在进行平方和,平方和有公式的,那成了
如果过了以k金币为结束的n天,那么就有一条方程
n * (n+1)=2 * k。即k=(sqrt(1+8 * n)-1)/2
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
int k = (sqrt(1 + 8 * n + 0.5) - 1) / 2;
int sum = (k * (k + 1) * (2 * k + 1)) / 6;
//求出剩下的部分
n -= k * (k + 1) / 2;
sum += n * (k + 1);
cout << sum;
return 0;
}
2.5991: 成绩
NOIP2017 普及组T1
就这样一个简单题,当时也是有人没做对,OI赛制提交了不能实时得到结果,解题时一定要小心谨慎
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a, b, c;
cin >> a >> b >> c;
printf("%.f", a * 0.2 + b * 0.3 + c * 0.5);
}
3.4843: 花生采摘
NOIP2004普及组T2
这也是个模拟题,需要注意没有两株花生株的花生数目相同
我们想要采摘到最多的花生数直接从最大的开始采摘即可,然后每次时间够就去摘,求的是曼哈顿距离
#include <bits/stdc++.h>
using namespace std;
struct T
{
//用结构体存坐标和数量及时间。
int x, y, time, w;
} a[405];
int cmp(T a,T b)
{
return a.w>b.w;
}
int main()
{
int m, n, t;
cin >> m >> n >> t;
//记录有花生的个数
int tot = 0;
for (int i = 0; i < m; i++)
for (int j = 0, x; j < n; j++)
{
cin >> x;
if (x > 0)
{
//下面有花生的时候就存储,记得下标从1开始
a[tot++] = {i+1,j+1,0,x};
}
}
//从大到小排序
sort(a,a+tot,cmp);
int ans=0;
//枚举每个花生
for (int i = 0; i < tot; i++)
{
if (i == 0)
{
//第一个花生多多一开始可以跳到第一个最多花生的所在列。
a[i].time = a[i].x + 1;
}
else
{
//不是第一个的话就加上与前一个的坐标差再加采摘时间。
a[i].time = a[i - 1].time + abs(a[i].x - a[i - 1].x) + abs(a[i].y - a[i - 1].y) + 1;
}
//如果数据合法那么就把花生数加上
if (a[i].time + a[i].x <= t)
ans += a[i].w;
}
cout << ans;
return 0;
}
也有人深搜的,不过这个深搜和循环也基本一样啊
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct p p;
struct p
{
int x,y,num;
}s[405];
int m,n,k,index,ans;
int a[25][25];
bool cmp(p a,p b)
{
return a.num>b.num;
}
void dfs(int x)
{
int tmp,dis;
if(x>=index)
return;
if(x==0)
dis=s[0].x;
else
dis=abs(s[x-1].x-s[x].x)+abs(s[x-1].y-s[x].y);
tmp=k-dis-1;
if(tmp>=s[x].x)///能回去
ans+=s[x].num,k=k-dis-1,dfs(x+1);
return;
}
int main()
{
cin>>m>>n>>k;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
if(a[i][j])
s[index].x=i,s[index].y=j,s[index++].num=a[i][j];
}
sort(s,s+index,cmp);
dfs(0);
cout<<ans<<'\n';
return 0;
}
4.4869: 寻宝
NOIP2012普及组T2
真正的模拟题
指示牌上有一个数字x,表示从这个房间开始按逆时针方向选择第x个有楼梯的房间,x的大小是1,000,000,如果直接上肯定是超时的。有没有方法能够不超时呢,我们可以使用取余,也就是考虑下周期性问题
%10会得到[0,10),对该层楼梯门个数进行取余,会出现0导致我们现在的门又没楼梯。为了避免这种情况,房间编号我们可以从1开始,0用来存储本层楼梯通往上一层的楼梯个数。取余个数然后加上a[i]0,这样就没有问题了
#include <bits/stdc++.h>
using namespace std;
//数组不要开小了,我开小get WA一次
const int N = 10005, M = 105;
int n, m, a[N][M], num[N][M];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
scanf("%d%d", &a[i][j], &num[i][j]);
//a[i][0]储存本层有多少楼梯通往上一层
if (a[i][j])
a[i][0]++;
}
int t, ans = 0;
cin >> t;
//房间编号往后挪了1
t++;
for (int i = 1; i <= n; i++)
{
ans = (ans + num[i][t]) % 20123;
//+a[i][0]是为了防止模了之后为0(包含本层只有一个楼梯)
int x = num[i][t] % a[i][0] + a[i][0];
t--;
while (x)
{
t++;
if (t > m)
t = 1;
if (a[i][t])
x--;
}
}
cout << ans;
return 0;
}
5.4876: 转圈游戏
NOIP2013提高组Day1T1
也就是1次你走到(x+m)%n的位置,10 ^ k次为(x+ m * 10 ^ k)%n的位置
满足随时取余定理,可以直接用快速幂进行求解
#include <bits/stdc++.h>
using namespace std;
int ksm(int a, int b, int Mod)
{
int ans = 1, t = a;
while (b)
{
//2进制位是1,就乘上,&按位与运算
if (b & 1)
ans = ans * 1LL * t % Mod;
t = t * 1LL * t % Mod;
//每次都/2,和右移(>>)一位相同
b >>= 1;
}
return ans;
}
int main()
{
int n, m, k, x;
cin >> n >> m >> k >> x;
cout << (x % n + m % n * ksm(10, k, n) % n) % n;
return 0;
}
6.4879: 积木大赛
NOIP2013提高组Day2T1
不用线段树,也不用递归,可以直接模拟
我们可以把序列分成(a1,..ai)(ai+1,...aj)......(ak,...an)多个非递减序列。
然后所有段中最大值的和减去除第一段外的段的最小值,那么直接记录两个数字的差是否可以呢
设q为左边一堆高度,p为右边一堆高度,s为总摆放次数。
1.q<p,即左边的一堆比右边矮,左边的一堆摆完后,右边的还差一点,那么摆放次数s加上两堆的高度差p-q(相当于摆好了右堆)。
2.q>=p,即左边的一堆比右边矮,说明只要左边的一堆堆好了,那么右边的一堆也肯定堆好了,所以不需要增加摆放次数s。
所以猜测是正确的
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, last = 0, ans = 0;
cin >> n;
for (int i = 0,x; i < n; i++)
{
cin >> x;
//左边低,需要加上
if (x > last)
ans += (x - last);
last = x;
}
cout << ans << endl;
}
7.4886: 生活大爆炸版石头剪刀布
NOIP2014提高组Day1T1
直接写出这个输赢表即可,一个一个写if累死了,同理的还有TZOJ5137: 骰子
#include <bits/stdc++.h>
using namespace std;
//直接写出这个输赢表
int ce[5][5] = {
0, -1, 1, 1, -1,
1, 0, -1, 1, -1,
-1, 1, 0, -1, 1,
-1, -1, 1, 0, 1,
1, 1, -1, -1, 0};
int a[205], b[205];
int main()
{
int n, na, nb;
cin>>n>>na>>nb;
for (int i = 0; i < na; i++)
cin >> a[i];
for (int i = 0; i < nb; i++)
cin >> b[i];
int apos = 0, bpos = 0, awin = 0, bwin = 0;
for (int i = 1; i <= n; i++)
{
if (ce[a[apos]][b[bpos]] == 1)
awin++;
if (ce[a[apos]][b[bpos]] == -1)
bwin++;
apos++;
bpos++;
//到尾从头开始
if (apos == na)
apos = 0;
if (bpos == nb)
bpos = 0;
}
cout<<awin<<" "<<bwin;
return 0;
}
本文来自博客园,作者:暴力都不会的蒟蒻,转载请注明原文链接:https://www.cnblogs.com/BobHuang/p/13898850.html