12月月赛题解
问题 A: 求区间最大值
题目描述
给你一个长度为n的序列{a_1,a_2…a_n},下标从1到n,Q个询问,每次询问给出一个L和R,你需要输出最大的a_i,(L<=i<=R)
输入
单组数据
第一行给出n,(n<=1e6)
第二行有n个数代表{a_1,a_2…a_n},(a_i不超过int范围)
第三行给出q,代表有q个询问,(q<=1e6)
接下来q行每行给出两个数字代表L,R,(1<=L<=R<=n)
输出
对于每个询问,输出最大值
样例输入
4
2 1 3 4
2
1 2
1 4
样例输出
2
4
题解
线段树裸题
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
int a[1000000];
int T[1000001*4];
inline void build(int l,int r,int rt){
if(l==r){T[rt]=a[l];return;}
build(lson);
build(rson);
T[rt]=max(T[rt<<1],T[rt<<1|1]);
}
inline int query(int l,int r,int rt,int L,int R){
if(l>=L && r<=R)return T[rt];
int ret=-1;
if((l+r)/2>=L)ret=max(ret,query(lson,L,R));
if((l+r)/2+1<=R)ret=max(ret,query(rson,L,R));
return ret;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,n,1);
int q;
scanf("%d",&q);
while(q--){
int l, r;
scanf("%d %d",&l,&r);
printf("%d\n",query(1,n,1,l,r));
}
return 0;
}
问题 B: 服务器
题目描述
Bob的实验室中有n台服务器可以用来处理任务.每台服务器有一个独特的id–是一个从1到n的整数.
现在有q个任务要来,其中第i个任务的定义包含三个整数: ti –
这个任务到来的时刻(以秒为单位), ki –这个任务要 ki台服务器共同处理, di –处理这个任务时每台服务器所需要的时间.保证输入的所有ti是不同的.
为了完成第i个任务,你需要ki 台服务器在 ti秒没有被占用.一旦一台服务器开始执行任务的时候,他在接下来的di 秒将处于忙碌状态,即他将于ti, ti + 1, …, ti + di - 1秒处于忙碌状态.为了完成第i个任务,将用到ti时刻没有被占用的 ki 台id最小的服务器.如果 ti时刻没有被占用的服务器不足 ki ,那么这个任务将被忽略.
写一个程序判断哪些任务将被执行,那些任务将被忽略.
输入
输入包含一组数据
第一行包含两个整数n和q (1 ≤ n ≤ 100, 1 ≤ q ≤ 105),表示服务器的数量和任务的数量
接下来的q行,每行包含三个整数 ti, kiand di (1 ≤ ti ≤ 106, 1 ≤ ki ≤ n, 1 ≤ di ≤ 1000)表示第i个任务到来的时刻(秒),需要多少台服务器来运行以及每台服务运行他所需要的时间.任务将以字典序的顺序给出,并且每个任务的到来时间都不相同.
输出
打印q行,如果第i个任务将被服务器执行,在第i行打印运行第i个任务的服务器的id之和,否则打印-1.
样例输入
4 3
1 3 2
2 2 1
3 4 3
样例输出
6
-1
10
题解
按照描述模拟就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cstring>
#include<string>
using namespace std;
const int maxsize = (int)(2e5 + 7);
struct node
{
int t,k,d;
int id;
bool operator<(node b)
{
return t<b.t;
}
};
node D[maxsize];
int B[107];
int BB[107];
int Ans[maxsize];
int main()
{
int n,q;
cin>>n>>q;
for(int i=0;i<q;i++)
{
scanf("%d%d%d",&D[i].t,&D[i].k,&D[i].d);
D[i].id = i;
}
memset(Ans,-1,sizeof(Ans));
for(int i=0;i<q;i++)
{
int bbcnt = 0;
int sum = 0;
for(int j=0;j<n&&bbcnt<D[i].k;j++)
{
if(B[j]<=D[i].t)
{
BB[bbcnt++] = j;
sum+=j+1;
}
}
if(bbcnt==D[i].k)
{
for(int j=0;j<bbcnt;j++)
{
B[BB[j]] = D[i].t+D[i].d;
}
Ans[D[i].id] = sum;
}
}
for(int i=0;i<q;i++)
{
printf("%d\n",Ans[i]);
}
return 0;
}
问题 C: 机器人
题目描述
有编号1-n的n个格子,机器人从1号格子顺序向后走,一直走到n号格子,并需要从n号格子走出去。机器人有一个初始能量,每个格子对应一个整数A[i],表示这个格子的能量值。如果A[i] > 0,机器人走到这个格子能够获取A[i]个能量,如果A[i] < 0,走到这个格子需要消耗相应的能量,如果机器人的能量 < 0,就无法继续前进了。问机器人最少需要有多少初始能量,才能完成整个旅程。
例如:n = 5。{1,-2,-1,3,4} 最少需要2个初始能量,才能从1号走到5号格子。途中的能量变化如下3 1 0 3 7。
1e9>=n>=1
-1e5<=A[i]<=1e5
输入
给定一个n,接下来n行,每行一个数字,第i行的数字是A[i],表示这个格子能获取的能量
输出
输出结果为一个数字,代表机器人最少需要有多少的初始能量
样例输入
5
1
-2
-1
3
4
样例输出
2
题解
遍历一遍数组内所有元素,用on的时间复杂度可以预处理处数组里所有元素的前缀和(sum[i] = sum[i-1]+a[i]),再遍历一次sum数组,sum数组中的最小值的就是答案(注意要输出这个数的相反数)
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int main(void)
{
int i,j,n;
long long ans=2100000000,a[100100],sum=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
if(i==0)
sum=a[i];
else
sum=a[i]+sum;
ans=min(ans,sum);
}
if(ans>=0)
printf("0\n");
else
printf("%lld\n",0-ans);
return 0;
}
问题 D: 最后一个是谁?
题目描述
有n个人围成一圈,顺序排号。从第一个人开始报数(第一个报1,第二个报2……),凡报到m的人退出圈子(下一个人从1开始报),问最后留下的是原来第几号的那位。
输入
多组测试数据 t;
第一行输入t,1<=t<=10.
接下t行,每行两个整数,n,m 1<=n<=1000,1<=m<=1000.
输出
输出t行,每行一个整数。
样例输入
2
468 335
501 170
样例输出
88
393
题解
模拟,循环的实现就是迭代i对当前剩余人数取模,直到剩余人数为1时停止。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int i;
int n,m;
int k,j;
scanf("%d%d",&n,&m);
int *Array=new int[n];
for(i=0;i<n;i++)
{
Array[i]=i+1;
}
i=1;
k=0;
for(j=0;k<n-1;j=++j%n)
{
if(Array[j]!=0)
{
if(i==m)
{
k++;
Array[j]=0;
i=1;
}
else
{
i++;
}
}
}
for(i=0;i<n;i++)
{
if(Array[i]!=0)
{
printf("%d\n",i+1);
break;
}
}
}
return 0;
}
问题 E: 三角
题目描述
将1,2,······,9共9个数排成下列形态的三角形。
a
b c
d e
f g h i
其中:a~i分别表示1,2,······,9中的一个数字,并要求同时满足下列条件:
(1)a < f < i;
(2)b < d, g < h, c < e
(3)a+b+d+f=f+g+h+i=i+e+c+a=P
输入
边长之和P
输出
所有满足上述条件的三角形的个数以及其中的一种方案。
若有多种方案输出字典序最小的那种。若无解输出NO。
样例输入
21
样例输出
4
3
2 4
9 6
7 1 5 8
题解
a+b+d+f=P,枚举a,b,d,根据f=P-a-b-d计算出f
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
bool v[10];
int p,a[10],b[10],ans=0;
bool work(int step,int x) {
if(v[x])return 0;
if(step==2 || step==3 || step==7)return 1;
if(step==4)return x>a[2];
if(step==5)return x>a[3];
if(step==6)return (x>a[1])&&(a[1]+a[2]+a[4]+x==p);
if(step==8)return x>a[7];
if(step==9)return (x>a[6])&&(a[6]+a[7]+a[8]+x==p) && (a[1]+a[3]+a[5]+x==p);
return 1;
}
void dfs(int step){
int i,j,k;
if(step>=9) {
ans++;
if(ans==1)
for(i=1;i<=9;i++)
b[i]=a[i];
return;
}
for(i=1;i<=9;i++)
if(work(step+1,i)){
v[i]=1;
a[step+1]=i;
dfs(step+1);
v[i]=0;
}
}
int main()
{
while (~scanf("%d",&p)){
for(int i=1;i<=9;i++){
v[i]=1;
a[1]=i;
dfs(1);
v[i]=0;
}
if(ans==0)printf("NO\n");
else {
printf("%d\n%d\n",ans,b[1]);
printf("%d %d\n",b[2],b[3]);
printf("%d %d\n",b[4],b[5]);
printf("%d %d %d %d\n",b[6],b[7],b[8],b[9]);
}
}
return 0;
}
问题 F: 室友A的PY交易
题目描述
CC和TT在宿舍忙着写课设,他们决定由下述游戏的败者去拿外卖:
室友A想一个[1,N]中的数字X,两人轮流猜一个猜一个数字,恰好猜中X的人算负;否则室友A将告诉两人当前猜的数字是比X大还是比X小,这样一来猜测的范围就会变小(下一轮猜的数必须在X所在的那一半区间内)。初始范围是[1,N]。
室友A已经看透了一切,私下告诉了两人X是多少。现在,CC和TT都知道X是多少,且两个人都采取最优策略。若总是CC先猜,求X∈[1,N]可以使TT获胜的X的数量。
输入
第一行一个整数T表示数据组数。
接下来T行,每行一个正整数N。
1 <= T <= 100000
1 <= N <= 10000000
输出
T行每行一个整数表示答案。
样例输入
1
3
样例输出
1
题解
可以说是最简单的博弈题了,就是直接在浏览器写了交上去抢一血那种(:з)∠)
数轴抽象成一根棍子,中间X的位置有炸弹,两人轮流从任一端切去一段,先切到炸弹的人输。
设想X在正中间时,先手必败,因为先手切去一段破坏左右平衡后,后手可以在另一侧模拟一样的操作,将棍子恢复平衡。
那么同理,X不在正中间时,先手必胜,先手创造平衡条件即可。
棍子长度为奇数时,只有X在正中间时后手胜,输出1
长度为偶数时,输出0
这类博弈题目还是蛮有趣的,关键词包括“双方使用最优策略”
可以从NIM博弈(取石子游戏)开始学习,百度一搜一大把
这篇回答也不错https://www.zhihu.com/question/29910524
在正规比赛中,博弈一般是作为一种思想出现,与树、图等结构结合,而不是什么取石子、切棍子裸题。
#include <stdio.h>
int main()
{
freopen("test2.in", "r", stdin);
freopen("test2.out", "w", stdout);
int T, N;
scanf("%d", &T);
while(T--)
{
scanf("%d", &N);
printf("%d\n", N % 2);
}
return 0;
}
问题 G: 小明的游戏
题目描述
小明喜欢数字,现在小明想把一个数字拆分成若干个奇数的乘积,但他不知道
能不能拆分成功,你能帮帮他么
给你n个数,每个数都在int范围内
0 < n <= 1e5
单样例
输入
n
x1x2…xn
输出
n行,每行一个输出”YES”或”NO”(不包括引号)
样例输入
2
3 6
样例输出
YES
NO
题解
#include<bits/stdc++.h>
using namespace std;
int main(int argc, char const *argv[])
{
int n,x;
cin >> n;
for(int i=1;i<=n;i++){
cin >> x;
printf("%s\n",x%2 ? "YES" : "NO" );
}
return 0;
}
问题 H: 值日生
题目描述
八年级的Vova今天在课堂上值班。上课之后,他走进办公室洗板子,并在上面找到了n号。他问这个数字是什么,数学老师Inna Petrovna回答Vova说,n是一年级学生算术任务的答案。在教科书中,给出了某个正整数 x。n为十进制x加上各位上的数字的 和。
由于数字n很小,Vova很快就猜到了在教科书中可能出现哪个x。现在他想得到一个程序,它将搜索任意值为n的所有合适的x值,或者确定这个x不存在。为Vova写一个这样的程序
输入
第一行包含整数n(1≤ n ≤10^9)。
输出
在第一行打印一个整数k 表示满足要求的方案
后k行按照升序打印满足要求的数字
样例输入
21
20
样例输出
1
15
0
提示
15+1+5=21,只有一个满足要求
题解
最多也就是个9位数,因此最多就是在原来的数字基础上加9*9=81,大可以直接写100
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=10000;
bool judge(int num,int ans){
int tmp=num;
while(num!=0){
int tm=num%10;
num/=10;
tmp+=tm;
}
if(tmp==ans)
return true;
else
return false;
}
int main(){
int n;
while(~scanf("%d",&n)){
std::vector<int> v;
for(int i=max(1,n-100);i<=n;i++){
if(judge(i,n))
v.push_back(i);
}
printf("%d\n",v.size());
for(int i=0;i<v.size();i++){
printf("%d\n",v[i]);
}
}
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)