zoukankan      html  css  js  c++  java
  • 20181014NOIP模拟

     

    SDOI模拟赛 #9

    2018.10.14 8:00~11:30

    Powered By _C_H_M_ , Marser

    (Please Read The Instructions On This Page Carefully)

    一、题目概览

    题目名称

    流星

    Hash键值

    麦田

    灯光

    紫罗兰

    英文名称

    meteor

    hash

    field

    lighting

    violet

    可执行文件名

    meteor

    hash

    field

    lighting

    violet

    输入输出文件

    meteor.in/out

    hash.in/out

    field.in/out

    lighting.in/out

    violet.in/out

    时间限制

    1000 ms

    1000 ms

    150 ms

    1000 ms

    5000ms

    空间限制

    128 MB

    128 MB

    128 MB

    128 MB

    512MB

    题目类型

    传统型

    传统型

    传统型

    传统型

    传统型

    编译命令

    -lm

    -lm

    -lm

    -lm -Wl,--stack=102400000

    -lm -Wl,--stack=102400000     -O2

    测试点(包)数目

    20

    3

    10

    10

    2

    测试点是否等分

    二、注意事项

    1. 文件名(源程序名和输入输出文件名)必须使用小写。

    2. 评测在windows下lemon中进行。输入输出long long int 类型数值请使用cin/cout 或“%lld”。

    3. main函数的返回值类型必须是int,程序正常结束时返回值必须是0。

    4. 题目较水,请AK的同学不要D出题人,没AK的同学也不要D出题人。赛后会向AK的同学、前三名同学以及AC附加题的同学发放奖品。

    5. 本次采用OI赛制,在比赛结束后统一交题,祝大家RP=INT_MAX。

    第一题:

    题目:

    流星(meteor)

    【题目背景】

    我带着深藏骨血的仇恨与酝酿多年的阴谋

    把自己变成一个死而复生的幽灵 沉入沼泽,沉入深渊

    我想埋下腐烂的根系 长出见血封喉的荆棘 刺穿这个虚伪的文明

    我到了淤泥深处…… 捡到了一颗星星。

    晨光起于白塔尖顶,终将铺满阴霾之地。

    【题目描述】

    Marser正在和副词看星星。这时,他们发现了一颗流星划过天际。Marser出于习惯,记录下了这颗流星出现和消失的位置。Marser用两组坐标来描述这两个位置。你可以认为它们被Marser放在了一个原点由Marser指定的笛卡尔坐标系中。

    现在,副词为了考验Marser的智商,想问他一个问题:按照Marser的坐标系定义,这颗流星一共经过了多少个格点?这里,格点被定义为坐标均为整数的点。

    Marser用了1ms就完成了这个问题,于是他想用这个问题来测试您的智力。当然,为了简化您的操作,您可以把流星的运动轨迹看成一条直线。这样,您可以把这个问题转化为求一条线段除了端点外经过了多少个格点。

    【输入格式】

    从文件meteor.in中读入。

    读入两行,每行两个整数x,y,表示线段的两个端点的坐标。

    【输出格式】

    输出到文件meteor.out中。

    输出一行一个整数,表示除了两个端点外,线段经过的格点数量。

    【输入输出样例】

    meteor.in

    meteor.out

    1 11

    5 3

    3

    【数据范围与约定】

    解析:

           我们想象把这条线段的一个端点已到原点,则另一点变为(x2-x1,y2-y1),所以这道题目就变为在函数y=(y2-y1)/(x2-x1)x中,(0<x<=x2-x1)找到有多少个整数x使得y也为整数,我们代入一个数值去算,那么必然是先将(y2-y1)/(x2-x1)化为最简形式,x2-x1/x2-x1(化解后)即为答案,其实这个值就是他们之前化解的倍数即为gcd(x2-x1,y2-y1);

    错点:

    1、数据范围,注意使用long long定义;

    2、特判端点重合,线段与x,y轴平行的情况

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #define ll    long long
    using namespace std;
    ll gcd(ll x,ll y){
        if(y>x)return gcd(y,x);
        if(y==0)return x;
        return gcd(y,x%y);
    } 
    int main(){
        freopen("meteor.in","r",stdin);
        freopen("meteor.out","w",stdout);
        ll x1,x2,y1,y2;
        cin>>x1>>y1>>x2>>y2;
        if(x1==x2&&y1==y2){printf("0");return 0;}
        x2-=x1;
        y2-=y1;
        if(x2<0)x2-=2ll*x2;
        if(y2<0)y2-=2ll*y2;
        ll d=gcd(x2,y2);
        if(y2==0)printf("%lld",x2-1);
        else if(x2==0)printf("%lld",y2-1);
        else printf("%lld",d-1);
        return 0;
    } 
    View Code

     第二题:

    题目:

    Hash键值(hash)

    【题目背景】

    所有的苦难与背负尽头,

    都是行云流水般的此世光阴。

    一生所渴求的,全都伤人至深。

    而一生所憎恶的,全都令人魂牵梦萦。

    【题目描述】

    Marser沉迷hash无法自拔,然而他发现自己记不住hash键值了……

    Marser使用的hash函数是一个单纯的取模运算,每一个数i被对应到i mod p。他现在有一个数列,他采用这种方法,把每一个数对应到一个键值i mod p。他想知道对于给定的模数p和键值r,所有对应到该键值的数的和为多少。同时,Marser可能会发现他的数列出了一些问题,所以他还想随时更改数列中任意一项的值。

    现在Marser有q个请求,每个请求可能是修改或是询问。对于每一个询问,你需要给出正确的答案。如果你不能在1s内正确回答所有询问,Marser就会让hotwords把你给续了。

    【输入格式】

    从文件hash.in读入。

    第一行两个整数n,q,表示数列长度和请求数量。

    第二行n个整数,表示初始的序列。

    接下来m行,每行三个整数opt,x,y;

    若opt=1,则询问在mod x时,所有对应到键值y的数的和。

    若opt=2,则将数列第x项修改为y。

    【输出格式】

    输出到文件hash.out中。

    对于每个询问,输出相应的答案。

    【输入输出样例1】

    hash1.in

    hash1.out

    10 5

    1 2 3 4 5 6 7 8 9 10

    1 2 1

    2 1 20

    1 3 1

    2 5 1

    1 5 0

    25

    41

    11

    【输入输出样例2】

    见下发文件中的hash2.in/ans

    该样例满足子任务二的性质。

    【输入输出样例3】

    见下发文件中的hash3.in/ans

    该样例满足子任务三的性质。

    【数据范围与约定】

    解析:

    其实子任务1和2都较容易实现,(2尚未成功),而总体的解决方案其实是在这两个之间折中选择

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    int n,m,q;
    int a[101010],sum[1010][1010];
    int opt,x,y;
    int main(){
        freopen("hash.in","r",stdin);
        freopen("hash.out","w",stdout);
        scanf("%d%d",&n,&q);
        m=sqrt(n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            for(int j=1;j<=m;j++)sum[j][i%j]+=a[i];
        }
        int ans=0;
        while(q--){
            scanf("%d%d%d",&opt,&x,&y);
            if(opt==1){
                if(x<=m)printf("%d
    ",sum[x][y]);
                else{
                    ans=0;
                    for(int i=y;i<=n;i+=x)
                        ans+=a[i];
                    printf("%d
    ",ans);
                }
            }
            else{
                for(int i=1;i<=m;i++)
                    sum[i][x%i]=sum[i][x%i]-a[x]+y;
                a[x]=y;
            }
        }
        return 0;
    }
    View Code

     第三题:

    题目:

    麦田(field)

    【题目背景】

    我心里有一簇迎着烈日而生的花,

    比一切美酒都要芬芳,

    滚烫的馨香淹没过稻草人的胸膛,

    草扎的精神,从此万寿无疆。

    凝视深渊的人,深渊也在凝视你。

    我不是凝视深渊的人,我就是深渊。

    【题目描述】

    Marser来到了一片麦田。他想穿过这片麦田,去找副词一起学习。

    但是,他发现这片麦田有一些特殊的性质。我们可以把麦田抽象成一片的网格,每个格子上都有一个数字。同时,Marser按如下的方式表示前进的方向:

    如果往与所在格子上数字相同的方向前进,Marser不需要花费体力;而往其他方向前进时,Marser就需要额外花费1单位的体力。

    现在,Marser想知道,从给定的起点前进到给定的终点,最少需要消耗多少体力?

    【输入格式】

    从文件field.in读入。

    第一行两个整数n,m,表示麦田的大小。

    接下来n行,每行一个长度为m的字符串,表示每个格子上的数字。

    接下来一行,四个整数,表示起点和终点的位置。

    【输出格式】

    输出到文件field.out中。

    输出一行一个整数,表示最少需要消耗的体力。

    【输入输出样例1】

    field1.in

    field1.out

    5 5

    04125

    03355

    64734

    72377

    02062

    4 2 4 2

    0

    【输入输出样例2】

    field2.in

    field2.out

    5 5

    04125

    03355

    64734

    72377

    02062

    4 5 1 4

    2

    【输入输出样例3】

    见下发文件中的field3.in/ans

    该样例满足。

    【数据范围与约定】

    解析:

    尝试模拟SPFA的SLF优化,就是若dis[j]<dis[i],就加到队头,否则加到队尾,对于这道题来说,就只有0和1两种权值,所以0加队首,1加队尾

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    int mod=1000000;
    int dis[1010][1010];//以x,y为起点,算到每个位置的花费;
    int que[1010101][2];//因为有x,y两个坐标,所以是2
    int dx[8]={-1,-1,0,1,1,1,0,-1};//为了后面判断后面要走0还是1
    int dy[8]={0,1,1,1,0,-1,-1,-1};//要根据八个位子的数字来修改x,y 
    char map[1010][1010];
    int n,m,x1,y1,x2,y2;
    int main(){
        freopen("field.in","r",stdin);
        freopen("field.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%s",map[i]+1);
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        dis[x1][y1]=0;
        int he=0,tai=1;
        memset(dis,0x3f,sizeof(dis));
        que[he][0]=x1,que[he][1]=y1;
        dis[x1][y1]=0;
        while(he!=tai){
            int x=que[he][0],y=que[he][1];he++; 
            if(x==x2&&y==y2)break;
            for(int i=0;i<8;i++){
                int xx=x+dx[i],yy=y+dy[i];
                if(!xx||!yy||xx>n||yy>m)continue;//这样写很方便;
                if(dis[xx][yy]>dis[x][y]+(map[x][y]-'0'!=i)){
                    dis[xx][yy]=dis[x][y]+(map[x][y]-'0'!=i);//如果条件成立就+1
                    if(map[x][y]-'0'!=i){que[tai][0]=xx,que[tai][1]=yy;tai++;} 
                    else {he--;que[he][0]=xx,que[he][1]=yy;}//重点,因为先he就加过了所以-回来 
                } 
            }
        }
        printf("%d",dis[x2][y2]);
    }
    View Code

    总结:

    对于这类的题,要么不费力气,要么费一点,都有同样的做法,显然用这种速度是极快的;这样写有两个很方便的地方,一个是if(!xx||!yy||xx>n||yy>m)continue;这样有效避免了很多无谓的重复,还有就是dis[xx][yy]=dis[x][y]+(map[x][y]-'0'!=i);,如果成立就加1,否则加0,这样写也很方便;

  • 相关阅读:
    Vertica 业务用户指定资源池加载数据
    Vertica 数据库知识汇总篇
    Oracle OCP 1Z0-053 Exam Topics
    Oracle 11gR2 RAC修改监听默认端口
    Oracle 11.2.0.4 RAC安装最新PSU补丁
    Openfiler配置RAC共享存储
    ORACLE 11gR2 DG(Physical Standby)日常维护01
    oracle 存储过程 返回结果集
    exception javax.crypto.BadPaddingException: Given final block not properly padded
    plsql 连接oracle数据库的2种方式
  • 原文地址:https://www.cnblogs.com/linzeli/p/9795139.html
Copyright © 2011-2022 走看看