--12月月赛题解--

来源:互联网 发布:csol控制台优化 编辑:程序博客网 时间:2024/04/30 10:39

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|1int 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(){    //freopen("in","r",stdin);    //freopen("out1","w",stdout);    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];//100*10^5int B[107];int BB[107];int Ans[maxsize];//sumint 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;    }    //sort(D,D+q);    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(){    //freopen("samplein_5.txt", "r", stdin);    //freopen("sampleout_5.txt", "w", stdout);    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()  {      //freopen("1.in","r",stdin);      //freopen("1.out","w",stdout);      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 longusing 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(){    // freopen("1.in","r",stdin);    // freopen("1.out","w",stdout);    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;}
原创粉丝点击