2018大连理工新生赛解题报告

Problem A: 打ACM真开心啊!

思路:假装没有这一题

roblem B: Zeratul与翻转黑白棋

思路:皮这一下很开心=W=!

Problem C: Type-B型时间芯片

思路:算一下 数量然后就输出……

代码:

    #include
using namespace std;
int n;
int dx[5]={0,1,0,-1};
int dy[5]={1,0,-1,0};
int main()
{
    char ch;int temp;
    scanf("%d",&n);scanf(" %c",&ch);
    int a[100];
    a[1]=1;
    for(int i=2;i<13;i++){
        a[i]=a[i-1]+2*(2*i-1);
    }
    for(int i=1;i<13;i++)
    {
        if(a[i]>n) {
            temp=i-1;
            break;
        }
    }
    for(int i=0;i=0;i--)
    {
        for(int j=0;j

Problem D: 世界线数的变动

Time Limit:3000/1000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:87   Accepted:20

[Submit][Status][Discuss]

Description

由于LabMem的工作需要,冈部经常在世界线间穿梭。不同世界线间的差别非常细微,确定当前处在哪一世界线成了困扰冈部的一个难题。好在他发现,世界线的变动只和nn个特定的数有关,这些数的和可以直接用来确定世界线。这组数被称为世界线数

 

只有两种情况可以引起世界线数变化。

情况一,每次跳跃世界线时,命运石之门都会给出三个整数l,r,xl,r,x,并将第ll个到第rr个世界线数统一赋值成xx。这三个整数毫无规律且变化无常,所以冈部只能在跳跃过程中将其一一记录。

情况二,一个名为的SERN组织有时会做一些实验,引起世界线的不稳定,这会导致冈部从某个世界线直接掉回到之前到过的一个世界线,并且世界线数变回当时的数值。

 

现在冈部正在进行一系列的世界线跳跃,他记录下了每次跳跃的l,r,xl,r,x三个参数。每次世界线不稳定时,他都会记录这次掉回的是第几次跳跃后的世界线。他将记录好的数据第一时间告诉你,并希望你能在第一时间帮他算出当前世界线数的和。

本题数据组数:4。

Input

第一行一个整数nn,表示世界线数的个数。

第二行nn个整数aiai,代表世界线数

第三行一个整数mm,代表即将发生的事件个数。

接下来mm行,每行描述一个事件。有如下三种输入

1 ll rr xx(表示发生情况一事件,世界线数按情况一中描述改变)

2 tt(表示发生情况二事件,冈部掉回第tt个事件执行后,第t+1t+1个事件未执行时的世界线,并且保证只会掉到之前的世界线)

3(表示询问事件,输出当前世界线数的和)

1≤n,m≤10001≤n,m≤1000,1≤l≤r≤n,0≤t≤n,0≤x,ai≤10001≤l≤r≤n,0≤t≤n,0≤x,ai≤1000

Output

对于每个询问3,输出结果

Sample Input

5
1 2 3 4 5
4
1 2 4 6
3
2 0
3

Sample Output

24
15

HINT

 

注意,跳跃,回掉和询问都是事件

 

Zeratul看了这个题,大喊一声:这不是SB可持久化线段树吗?n和m的数据范围为什么不改成100000?

思路:这不是傻逼可chi'持久化线段树.....暴力吗......记录下状态就行。

        #include
using namespace std;
int n;int a[1010][1010];
int ans[1010];
int main()
{
    int t,m;int nowans;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i][0]);
    }
    scanf("%d",&m);int now=0;
    for(int mi=1;mi<=m;mi++)
    {
        int choi;
        scanf("%d",&choi);
        if(choi==3)
        {
            int sum=0;
            for(int i=1;i<=n;i++)
            {
                a[i][mi]=a[i][mi-1];
                sum+=a[i][mi];
            }
            printf("%d\n",sum);
        }
        if(choi==2)
        {
            int tiao;
            scanf("%d",&tiao);
            for(int i=1;i<=n;i++)
            {
                a[i][mi]=a[i][tiao];
            }
        }
        if(choi==1)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            for(int i=1;i<=n;i++)
            {
                a[i][mi]=a[i][mi-1];
                if(i>=x&&i<=y){
                    a[i][mi]=c;
                }
            }
        }
    }
    return 0;
}

Problem E: Big brother said the calculation(Easy ver.)

Time Limit:3000/1000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:75   Accepted:47

[Submit][Status][Discuss]

Description

 (我们永远的)大哥有很多的小弟(n个)。每一个小弟有一个智力值。现在小弟们聚集在了大哥身旁,排成了一队,等待大哥的检阅。n个小弟的智力值是一个1到n的排列。大哥在检阅小弟时,每次会选择一些相邻的小弟,让他们按照自己的智力值从小到大或从大到小顺序重新排队(没有被选择的小弟位置不变),以便他排除其中的二五仔。在大哥检阅完小弟之后,老仙突然来了。他十分想为难一下大哥,所以他问大哥其中某一个小弟的智力值是多少。大哥十分的慌,并不能回答这个问题,所以让你来帮他解决这个问题。如果你能够解决,大哥可能会赠与你守护者的三叉戟和并教你他的换家绝学。

本题数据组数:8。

Input

第一行3个整数nn,qq,kk,表示小弟的数目,大哥检阅小弟时让一些小弟重新排队的次数,以及最后老仙问他的是第几个小弟的智力值。

第二行n(1≤n≤20)n(1≤n≤20)个整数,表示每个小弟的智力值,保证符合题意,是11到nn的一个排列。

接下来q(1≤q≤20)q(1≤q≤20)行,每行3个整数aa,bb,t(1≤a≤b≤n,0≤t≤1)t(1≤a≤b≤n,0≤t≤1),表示他选择了第aa个到第bb个小弟(a,ba,b均包含)进行重新排列。若t=0t=0,则为从小到大;若t=1t=1,则为从大到小。

Output

 输出一个整数,代表在检阅之后第k个小弟的智力值是多少。

Sample Input

5 2 4
1 4 3 2 5
1 3 0
3 5 1

Sample Output

4

HINT

 

 对样例的解释:

 

第一次操作之后,排列变为:1 3 4 2 5

 

第二次操作之后,排列变为:1 3 5 4 2

 

第四个数是4,所以输出4。

 

[Submit][Status][Web Board]

思路:暴力模拟。。。

    #include
using namespace std;
int n;
int dx[5]={0,1,0,-1};
int dy[5]={1,0,-1,0};
int a[100];
 
int cmp(int x,int y){
    return x>y;
}
int main()
{
    int t,q;int x,y,choi;
    scanf("%d%d%d",&n,&t,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=t;i++)
    {
        scanf("%d%d%d",&x,&y,&choi);
        if(choi==0){
            sort(a+x,a+y+1);
        }
        else{
            sort(a+x,a+y+1,cmp);
        }
    }
    printf("%d",a[q]);
    return 0;
}               

 

Problem F: The world without "the HIM"

Time Limit:3000/1000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:103   Accepted:21

[Submit][Status][Discuss]

Description

想象一下,如果在遥远的将来,有一天,虵,离开了我们的世界。届时,无数事物都将随虵而去。比如1,9,2,6四个数码,就将不再存在。那么现在大膜法师Kyurem想让你为残酷的末世做一做心理准备,所以你需要能够回答以下两种问题:

1.在没有虵的世界里,第kk个正整数是多少?

2.在没有虵的世界里,nn是第几个正整数?

如前10个正整数是:3,4,5,7,8,30,33,34,35,37。

大膜导师Kyurem会考验你以上两种问题共计qq次,对于每次你都要立刻给出正确的结果。

本题数据组数:3

 

 

Input

输入数据第一行一个整数q(1≤q≤1000)q(1≤q≤1000),表示问问题的次数。

接下来qq行,每行2个整数。第一个数1或2,表示问的问题是1或2。若第一个数是1,第二个数表示k(1≤k≤109)k(1≤k≤109);若第一个数是2,第二个数表示n(1≤n≤109)n(1≤n≤109)。

 

Output

对于每一行输入,输出对应的答案。

 

Sample Input

2
1 5
2 5

Sample Output

8
3

HINT

 

输出的答案(如虵的寿命一样)可能超过int的范围,也就是说你可能需要使用其他范围更大类型如long long int,当然不限于此。

 

[Submit][Status][Web Board]

思路:就是六进制和十进制间的转换......

            #include
using namespace std;
int n;int f[6]={0,3,4,5,7,8};
long long num[40];int ni[11]{0,0,0,1,2,3,0,4,5,0};
int main()
{
    int t;long long k;int choi;
    scanf("%d",&t);
    num[0]=1;
    for(int i=1;i<=12;i++)
    {
        num[i]=num[i-1]*6;
       // printf("%lld\n",num[i]);
    }
    while(t--)
    {
        scanf("%d",&choi);
        if(choi==1)
        {
            scanf("%lld",&k);int flag=0;
            for(int i=11;i>=0;i--)
            {
                if(k/num[i]==0)
                {
                    if(flag==1) printf("0");
                }
                else{
                    printf("%d",f[k/num[i]]);
                    flag=1;
                }
                k=k-(k/num[i])*num[i];
            }
            printf("\n");
        }
        if(choi==2)
        {
            long long ans=0;int i=0;
            scanf("%lld",&k);
            while(k>0){
                ans+=ni[k%10]*num[i];i++;
                k/=10;
            }
            printf("%lld\n",ans);
 
        }
 
    }
 
}

Problem G: Geralt的佛系昆特牌

Problem G: Geralt的佛系昆特牌

Time Limit:7000/5000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:122   Accepted:16

[Submit][Status][Discuss]

Description

昆特牌是风靡巫师大陆的一种卡牌游戏。与大陆上其他商人一样,杰洛特非常喜欢这个游戏,直到他遇到了一个手中全是英雄牌的神棍……杰洛特觉得这个游戏不应该只靠卡牌好坏取胜,于是他设计了一种佛系昆特牌。

佛系昆特牌中只有战士鼓舞两种卡牌,战士可以对敌方造成一定点数的伤害(不同等级的战士牌造成的伤害不同),而鼓舞则可以提升战士的伤害点数(不同等级的鼓舞牌提升的点数也不同),鼓舞牌可以无限次使用,提升的伤害点数叠加。

游戏开始时,玩家需要选出 nn 张战士牌和 nn 张鼓舞牌,按顺序排好(编号1到 nn)。每一轮游戏,昆特牌系统给出两个随机数l,rl,r。代表这一轮对 ll 到 rr 号战士分别使用第 ll 到 rr 张鼓舞牌一次。最后一轮游戏结束后,将所有战士牌的伤害点数(包括鼓舞牌提升的点数)相加,便得到对敌人的伤害总数值。

杰洛特给你了nn张战士牌和nn张鼓舞牌的排列,他想让你算出在已知昆特牌系统给出的随机数的情况下,他的排列方案中每个战士牌的伤害数值是多少。

本题数据组数:3。

Input

第一行两个正整数nn和mm,代表选出nn张战士牌,游戏共有mm轮。

第二行nn个整数ai(0≤ai≤100)ai(0≤ai≤100),其中aiai代表ii位置战士牌的伤害点数。

第三行nn个整数bi(0≤bi≤100)bi(0≤bi≤100),其中bibi代表第ii张鼓舞牌可以提升的伤害点数。

之后的mm行,每行有两个正整数ll和rr,其中第ii行的数lili和riri代表第i轮昆特牌系统选出的两个随机数。

数据中1≤n,m≤106,1≤li≤ri≤n1≤n,m≤106,1≤li≤ri≤n。

 

Output

一行nn个整数,代表mm轮游戏后每个战士牌的伤害数值。

Sample Input

5 2
1 2 3 4 5
5 4 3 2 1
1 3
3 5

Sample Output

6 6 9 6 6

HINT

 

 你需要设计一个较为高效的算法,否则会TLE。

 

输入数据共有约40M,请使用较快的I/O方式。

思路:用一个差分数组记录一次加成,然后求前缀和就是该士兵鼓舞次数。(差分数组即d[i]=f[i]-f[i-1])

    #include
using namespace std;
int n;
int dx[5]={0,1,0,-1};
int dy[5]={1,0,-1,0};
int a[1000010];
int b[1000010];
int num[1000200];
int main()
{
    int m,q;int x,y,choi;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
       for(int i=1;i<=n;i++)
    {
        scanf("%d",&b[i]);
    }
    while(m--)
    {
        scanf("%d%d",&x,&y);
        num[x]++;num[y+1]--;
    }
    for(int i=1;i<=n+1;i++)
    {
        num[i]=num[i]+num[i-1];
    }
    for(int i=1;i<=n;i++)
    {
        printf("%d",a[i]+num[i]*b[i]);
        if(i!=n) printf(" ");
    }
    return 0;
}

Problem H: 程序的阅读是解题的第一步

Time Limit:3000/1000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:80   Accepted:11

[Submit][Status][Discuss]

Description

阅读并理解上图中的程序(s1,s2,s3为三个char类型数组),求出对于正整数xx和kk,调用f(x)f(x)后上图程序输出的第kk个字符是什么。

本题数据组数:11。

 

Input

前三行每行一个字符串,分别代表s1,s2,s3,字符串只含小写字母,长度不超过20。

第四行两个正整数x,kx,k,意义见描述。

数据保证x≤100,k≤1018x≤100,k≤1018

 

Output

输出一行一个字符,意义见描述。如果f(x)f(x)输出的总字符数小于kk输出gg。

 

Sample Input

ab
cd
ef
2 10

Sample Output

d

思路:设len[i]为f(i)输出字符串长度 则 len[i]=len[i-1]*2+strlen(s1)+strlen(s2)+strlen(s3); 那么可以o(1)判断要输出的字符是在5段中的哪一段然后递归即可。

            #include
using namespace std;
int n;
int dx[5]={0,1,0,-1};
int dy[5]={1,0,-1,0};
char s1[30];char s2[30];char s3[30];long long num[200];long long e18=1e18;
int len1,len2,len3;int big;
char findch(int x,long long k)
{
   // printf("%d %lld\n",x,k);
    if(x>big)
    {
        if(k<=len1) return s1[k-1];
        else
        return findch(x-1,k-len1);
    }
   if(k<=len1)
   {
       return s1[k-1];
   }
   if(k<=len1+num[x-1]&&x!=1){
    return findch(x-1,k-len1);
   }
   if(k<=len1+num[x-1]+len2)
   {
       return s2[k-len1-num[x-1]-1];
   }
   if(k<=len1+num[x-1]+num[x-1]+len2&&x!=1)
   {
       return findch(x-1,k-len1-num[x-1]-len2);
   }
    return s3[k-(len1+num[x-1]+num[x-1]+len2)-1];
}
int main()
{
    int m,q;int x,y,choi;long long k;
    scanf("%s",s1);    scanf("%s",s2);    scanf("%s",s3);
    scanf("%d",&x);scanf("%lld",&k);
    len1=strlen(s1);    len2=strlen(s2);    len3=strlen(s3);
    int len=strlen(s1)+strlen(s2)+strlen(s3);
    num[1]=len;
    for(int i=2;i<101;i++)
    {
        num[i]=2*num[i-1]+len;
       // printf("%lld\n",num[i]);
        if(num[i]>=e18){
                big=i;
               // printf("%lld %d\n",num[big],big);
             break;
        }
    }
    if(num[x]

 

Problem I: A quest with no intelligence

欧拉回路<======点这里

Problem J: Pokémon battle

极大极小值搜索

Problem K: Minitrue volunteer

kmp+dp

Problem L: Professional commentator of a stupid game

树状数组

Problem M: Big brother said the calculation

二分查找+线段树~~

你可能感兴趣的:(解题报告,ACM)