zoukankan      html  css  js  c++  java
  • 一场比赛:20170707

      今天考了一场让我差点爆0的比赛,似乎最初只有10分。其中一题数据有误,修正过后也只是多了60分。

      改得很辛苦啊!


    A:hao

    【问题描述】
      祖玛是一款曾经风靡全球的游戏,其玩法是:在一条轨道上初始排列着若干个彩色珠子,其中任意三个相邻的珠子不会完全同色。此后,你可以发射珠子到轨道上并加入原有序列中。一旦有三个或更多同色的珠子变成相邻,它们就会立即消失。这类消除现象可能会连锁式发生,其间你将暂时不能发射珠子。

      开发商最近准备为玩家写一个游戏过程的回放工具。他们已经在游戏内完成了过程记录的功能,而回放功能的实现则委托你来完成。

      游戏过程的记录中,首先是轨道上初始的珠子序列,然后是玩家接下来所做的一系列操作。你的任务是,在各次操作之后及时计算出新的珠子序列。
    【输入格式】
      第一行是一个由大写字母'A'~'Z'组成的字符串,表示轨道上初始的珠子序列,不同的字母表示不同的颜色。
      第二行是一个数字n,表示整个回放过程共有n次操作。
      接下来的n行依次对应于各次操作。每次操作由一个数字k和一个大写字母P描述,以空格分隔。其中, P为新珠子的颜色。若插入前共有m颗珠子,则k∈[0,m]表示新珠子嵌入之后(尚未发生消除之前)在轨道上的位序。
    【输出格式】
      输出共n行,依次给出各次操作(及可能随即发生的消除现象)之后轨道上的珠子序列。

      如果轨道上已没有珠子,则以“-”表示。
    【样例输入】
    ACCBA
    5
    1 B
    0 A
    2 B
    4 C
    0 A
    【样例输出】
    ABCCBA
    AABCCBA
    AABBCCBA
    -
    A
    【数据规模与约定】
    100%的数据满足 1<=n<=10^3,1<=m<=2*10^3。


      嗯。既然每次都要输出结果,那么直接上链表肯定最方便。使用双向链表,0号点连接了最前和最后,当了哨兵和边界,用起来比较方便、

      但是,充分考虑祖玛的规则之后(许多同学为了深度理解祖玛的规则……呵呵你懂的),我们发现如果有连续的并没有用,需要一个操作(a+b>=3),才能消去。此处操作只有插入,与消去一次后两端加和的连锁消去。此处很重要,举个例子。

      若初始序列为AAACCBB,此时AAA不会立即消去。若将C凑够3个,C将消净,但AAA仍不会消去。但若再插入一个A,凑成了AAAA才会消去。

      这是2个点。

      还有,初始序列为空呢?唉!scanf就不该用啊。

      又是2个点。

      所以,所以。

     1 #define PN "hao"
     2 #include <cstdio>
     3 #include <cstring>
     4 const int N = 5000;
     5 int prev[N], next[N], col[N], tail, stack[N], top=0;
     6 char ss[N];
     7 inline int insert(int k,int c) {
     8     int p=0;for( int i = 0; i <= k; i++,p=next[p] );
     9     col[++tail]=c;
    10     next[prev[p]]=tail;prev[tail]=prev[p];
    11     next[tail]=p;prev[p]=tail;
    12     return tail;
    13 }
    14 inline void clear(int p) {
    15     int x, y, tot=0;
    16     for(x=prev[p];x&&col[x]==col[p];x=prev[x],tot++);
    17     for(y=next[p];y&&col[y]==col[p];y=next[y],tot++);
    18     if(tot>=2) {
    19         next[x]=y;prev[y]=x;
    20         if(col[x]==col[y]) clear(x);
    21     }
    22 }
    23 int main() {
    24     freopen(PN".in","r",stdin);
    25     freopen(PN".out","w",stdout);
    26     int n, k, c;
    27     gets(ss);scanf("%d",&n);
    28     for( int len=strlen(ss), i = len-1; i >= 0; i-- ) insert(0,ss[i]);
    29     for( int i = 1; i <= n; i++ ) {
    30         scanf("%d",&k);while((c=getchar())==' '||c=='
    ');
    31         clear(insert(k,c));
    32         for( int p = 0; col[next[p]]; p=next[p] ) printf("%c",col[next[p]]);
    33         if(!col[next[0]]) printf("-");
    34         printf("
    ");
    35     }
    36     return 0;
    37 }
    hao

    B:kun

    【问题描述】

      栈是一种强大的数据结构,它的一种特殊功能是对数组进行排序。

      例如,借助一个栈,依次将数组1,3,2按顺序入栈或出栈,可对其从大到小排序: 1入栈;3入栈;3出栈;2入栈;2出栈;1出栈。

      在上面这个例子中,出栈序列是3,2,1,因此实现了对数组的排序。

      遗憾的是,有些时候,仅仅借助一个栈,不能实现对数组的完全排序。

      例如给定数组2,1,3,借助一个栈,能获得的字典序最大的出栈序列是3,1,2: 2入栈;1入栈;3入栈;3出栈;1出栈;2出栈。

      请你借助一个栈,对一个给定的数组按照出栈顺序进行从大到小排序。

      当无法完全排序时,请输出字典序最大的出栈序列。
    【输入格式】
    输入共2行。

    第一行包含一个整数n,表示入栈序列长度。

    第二行包含n个整数,表示入栈序列。

    输入数据保证给定的序列是1到n的全排列,即不会出现重复数字。

    【输出格式】
    仅一行,共n个整数,表示你计算出的出栈序列。
    【样例输入】
    3
    2 1 3
    【样例输出】
    3 1 2
    【数据规模与约定】
    对于30%的数据,1<=n<=10^3。

    对于60%的数据,1<=n<=10^5。

    对于100%的数据,1<=n<=10^6。


      一道很典型的关于栈的贪心题,当时细节没有想清楚。想着不停入栈,若栈顶为未弹出的最大的数,即弹出该数。最后全部弹出即可。

      但是但是,反例极其好举。最后发现,只要栈顶比所有未入栈的元素都大,便应弹出该数。正确性显然。但最开始调试出了谬误,应为“>=”而非“==”。

      忽然想起了NOIP的双栈排序。

     1 #define PN "kun"
     2 #include <cstdio>
     3 #include <cstring>
     4 const int N = 1001000;
     5 int n, stack[N], top, opt;
     6 bool ins[N];
     7 int main() {
     8     freopen(PN".in","r",stdin);
     9     freopen(PN".out","w",stdout);
    10     scanf("%d",&n);opt=n;
    11     memset(ins, false, sizeof(ins));
    12     for( int i = 1; i <= n; i++ ) {
    13         scanf("%d",&stack[++top]);ins[stack[top]]=1;
    14         while(top&&opt<=stack[top]) {
    15             printf("%d ",stack[top--]);
    16             while(ins[opt]) opt--;
    17         }
    18     }
    19     while(top) printf("%d ",stack[top--]);
    20     return 0;
    21 }
    kun

    C:nan
    【问题描述】
    我们有一个序列,现在他里面有三个数1,2,2。我们从第三个数开始考虑:
    1、第三个数是2,所以我们在序列后面写2个3,变成1,2,2,3,3 。

    2、第四个数是3,所以我们在序列后面写3个4,变成 1,2,2,3,3,4,4,4。
    那么你可以看到,这个序列应该是1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,… 。
    如果我们设一个数x最后出现的位置为last(x),那么现在我希望知道last(last(x))等于多少。
    【输入格式】
    第一行一个整数T,代表数据组数。
    接下来T行每行一个整数x。
    【输出格式】
    T行,每行一个整数,代表last(last(x))的值。
    【样例输入】
    3
    3
    10
    100000
    【样例输出】
    11
    217
    507231491
    【数据规模与约定】
    对于30%的数据,1<=n<=10^3 。
    对于60%的数据,1<=n<=10^6。
    对于100%的数据,1<=n<=10^9。


      从前有个神,说这题可以分块,分大块和小块,然后二分解决。于是这题怕了,便让他A了。

      设原序列中第i个数为ai。

      先不看询问,我们来分析一下。这个序列大概长这样:1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,9,10,10,10,10,10,11,11,11,11,11,12,12,12,12,12,12,…

      我们可以发现,它是1个1,2个2,2个3,3个4,3个5,4个6,4个7,4个8,5个9,5个10,5个11,6个12……

      连续的搞入一个块,每个块中有几种连续的数值,每种数值出现的次数是一样的。于是有:1种数各1次,2种数各2次,2种数各3次,3种数各4次,3种数各5次,4种数各6次,4种数各7次,4种数各8次,5种数各9次,5种数各10次……

      我们现在来观察。相邻块中各数值出现次数之差肯定是连续的。如果再把小块中连续数值种数相同的合作一个大块,便又可以发现:1种数拼出来的大块有1个小块,2种数拼出来的大块有2个小块,3种数拼出来的大块有2个小块,4种数拼出来的大块有3个小块,5种数拼出来的大块有3个小块……

      我们可以惊奇的发现,第i个大块中有ai个小块(这用该序列的定义很好证明),这些小块中显然有i种数值(定义),而第j个小块各数值出现j次,这些小块显然是连续的。

      现在来看问题。last(last(x))的意义是什么?一个数x最后出现的位置为last(x)。经观察得,last(last(x))即第x小块的最后一个数的位置(前x块的大小)。为什么呢?

      因为又定义可得,第x小块最后1个数为last(x),又根据定义一个数last(x)最后出现的位置(第x块最后一个数的编号)为last(last(x)),得证。

      于是,我们可以先预处理出各块的前缀和(大小)sumi,各块对应的ai,各块的前缀和(小块数)smalli。而10^9的范围内,块的总数约为438744。对于每个询问,二分锁定对应的大块。然后立马得解。

     1 #define PN "nan"
     2 #include <cstdio>
     3 #include <algorithm>
     4 const long long Big_num=670000;
     5 const long long MOD=1e9+7;
     6 long long aa[Big_num+10], siz, small[Big_num+10], sum[Big_num+10], T, n;
     7 //inline long long add(long long a,long long b) {return a+b>MOD?a+b-MOD:a+b;}
     8 int main() {
     9     freopen(PN".in","r",stdin);
    10     freopen(PN".out","w",stdout);
    11     aa[1]=1;aa[2]=aa[3]=2;siz=3;
    12     for( int i = 3; siz<Big_num+10; i++ ) for( int j = 1; j <= aa[i]&&siz<Big_num+10; j++ )aa[++siz]=i;
    13     for( int i = 1; i <= Big_num; i++ ) small[i]=small[i-1]+aa[i], sum[i]=(sum[i-1]+(small[i]-aa[i]+1+small[i])*aa[i]/2%MOD*i%MOD)%MOD;
    14     scanf("%I64d",&T);
    15     while(T--) {
    16         scanf("%I64d",&n);
    17         int pos=std::lower_bound(small+1,small+Big_num+1,n)-small;
    18         printf("%I64d
    ",(sum[pos-1]+(small[pos]-aa[pos]+1+n)*(n-small[pos]+aa[pos])/2%MOD*pos%MOD)%MOD);
    19     }
    20     return 0;
    21 }
    nan
  • 相关阅读:
    Java 抽象类
    Java 多态
    Java 重写与重载
    Java继承
    声卡驱动
    Sublime Text 3快捷键
    近年来世界各地ICO的花式骗局盘点
    区块链未能大爆发的影响因素有哪些?
    BCH分叉是一次站队博弈
    一文读懂百倍币的诞生背景
  • 原文地址:https://www.cnblogs.com/Doggu/p/test20170707.html
Copyright © 2011-2022 走看看