首页 > 代码库 > 【55测试】【字符串】【栈】【找规律】

【55测试】【字符串】【栈】【找规律】

  集训第二天,额,考崩了。

第一题 hao 大意:(这个名字就不要在意了,其实是祖玛游戏)

  模拟祖玛游戏的模式,给一个‘A‘~‘Z‘的字符串,然后有t个插入操作为 “ 添加后的在原字符串的位置 x  插入元素 c ”,字符串中有超过或等于 3 个相同的字符,则被消除,输出每次操作后剩余的字符串,如果为空,则输出“-”。

  样例:  ACCBA                      输出:  ABCCBA

        5                AABCCBA

        1 B             AABBCCBA

        0 A             -

        2 B             A

        4 C

        0 A

解:

  先开始我用的string,但是cin>>s并不能读取输入为空的情况,所以,就用char来做。插入和删除都用strcpy来做,这个还需熟练。然后每次插入一个后,用while来判断它及不断删除后能不能再继续删除,然后删除。

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 3005 6 using namespace std; 7 int n,pos,en; 8 char s[maxn]; 9 bool pd(int p)10 {11     int l=strlen(s),sum1=0,sum2=0;12     for (int i=p+1;i<l;i++)13        if (s[i]==s[p]) {14            en=i;15            sum1++;16        }17        else break;18     for (int i=p-1;i>=0;i--)19        if (s[i]==s[p]) {20            pos=i;21            sum2++;22        }23        else break;24     if (sum1+sum2+1>=3) return true;25     else return false;26 }27 void work(int st)28 {29     pos=st;30     while (1)31     {32         en=pos;//初值 33         if (strlen(s)==0) return ;//判断empty 34         if (pd(pos)) {35             int len=0;char tmp[maxn];36             //len=en-pos+1;37             strcpy(tmp,s+en+1);//******38             strcpy(s+pos,tmp);39             pos--;40         }41         else return ;42     }43 }44 void print()45 {46     int l=strlen(s);47     if (l==0) {48         printf("-");49         printf("\n");50     }51     else cout<<s<<endl;52     return ;53 }54 int main()55 {56     freopen("hao.in","r",stdin);57     freopen("hao.out","w",stdout);    58     s[0]=getchar();59     if(s[0]>=A&&s[0]<=Z) scanf("%s",s+1);60     else s[0]=0;61     62     cin>>n;63     for (int i=1;i<=n;i++)64     {65         int x;char a[maxn];66         int l=strlen(s);67         scanf("%d%s",&x,a);68         strcpy(a+1,s+x);69         strcpy(s+x,a);70         work(x);71         print();72     }73     return 0;74 }75 /*76     insert77     char tmp[1005];78     strcpy(tmp+1,s+k);79     strcpy(s+k,tmp);80     81     delete82     st--end--83     strcpy(tmp,s+end);84     strcpy(s+st,tmp);    85     86     */

第二题 kun 大意:(好吧,又来解释题目名字,就是栈排序)

  给一个数字序列,通过一个栈对这个序列进行排序,输出按最大字典序的排序后的序列。即:序列 2 1 3,可以通过 2,1入栈,输出3,再输出栈内的1,2得到最大字典序输出。而 3 1 2也可以通过一个栈,得到 3 2 1。数据保证为1~n的全排列。

解:

  先开始不懂什么是最大字典序,然后就乱搞,一个点都没有过。最大字典序,就是第一个数为最大的,也就是n(由题中的数据保证可知),然后下一个数不一定是第二大的,而应是相对而言在栈外或者在栈首的最大的。所以可以设一个cur表示当前的相对最大,cur从n~1递减;在1~n的循环中:如果不在栈内,那就让cur之前的全部入栈,while在栈内但不在栈首,那cur--,while在栈首,就输出并且cur--,如果循环到n,就输出栈内的所有元素。

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 1000005  6 using namespace std; 7 int n,s[maxn],head,stak[maxn],cur; 8 bool in[maxn]; 9 int main()10 {11     freopen("kun.in","r",stdin);12     freopen("kun.out","w",stdout);13     cin>>n;14     for (int i=1;i<=n;i++)15          scanf("%d",&s[i]);16     cur=n;17     for (int i=1;i<=n;i++)18     {19         while (in[cur]&&stak[head]!=cur) cur--;//在栈内,不能取 20         while (head!=0&&stak[head]>=cur)//栈顶有更优的解 21         {22             printf("%d ",stak[head]);23             if (stak[head]==cur) cur--;24             head--;25             while (in[cur]&&stak[head]!=cur) cur--;26         }27         if (s[i]==cur){//在栈外找到一个大的 28             cur--;29             printf("%d ",s[i]);30         }31         else {//不是优解,入栈 32             in[s[i]]=true;33             stak[++head]=s[i];34         }35         if (i==n){36             while (head!=0)37             {38                 printf("%d ",stak[head]);39                 head--;40             }41         }42     }43     return 0;44 }

第三题 nan 大意:(纯粹的找规律)

  有一个序列,前三项为1 2 2,然后从第三个数开始考虑:第三个数是2 ,所以在序列里添加 2个3, 得到1 2  2 3 3;

                            第四个数是3,所以在序列里添加 3个4,得到 1 2 2 3 3 4 4  4。

  last[x]表示数字x在序列中最后出现的位置,有t个询问,输出last[last[x]];

解:

  因为数据太大,存不下,所以打表过了30%。那么我们现在来找规律。

  1、序列: 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..........

  2、last[x]:1 3 5 8 11 15 19 23 28 33 38 44 50 56 62 69 76 83 90.......

  3、last[last[x]]:1 5 11 23 38 62 90 122.........

  那么我们把第3 行 last[last[x]]做差,此项减上一项,得到:1 4 6 12 15 24 28 32 45 50........

  改变一下就是:1*1, 2*2 ,2*3,3*4,3*5,4*6,4*7,4*8,5*9,5*10........

  即一个从1 递增的i  * 原序列 1 2 2 3 3 4 4 4 5 5.......

  再合并一些得到:1*1,2*(2+3), 3*(4+5), 4*(6+7+8),......

  每一项用等差和表示,(首项+尾项)*项数 / 2.

  然后用一个前缀和的方式记录答案。但是有可能询问的不是那一段的末尾,就需要用上一段的前缀和加上这一段。如当询问7的时候,7在 4 4 4 4中的第二个,所以就ans加上 到3 的前缀和,再加上从4开始的等差和就可以了。

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 1300005 6 #define P 1000000007 7 #define ll long long 8 using namespace std; 9 ll t,sum[maxn],cur,last[maxn];10 struct pp{11     ll l,r;12 };13 pp f[maxn];14 void pre()15 {16     f[1].l=f[1].r=1;17     f[2].l=2;f[2].r=3;18     last[1]=1;last[2]=3;cur=2;19     for (ll i=3;i<=maxn+1;i++)20     {21         last[i]=last[i-1]+cur;22         f[i].l=last[i-1]+1;23         f[i].r=last[i];24         if (i>=last[cur]) cur++;// >=25     }26     for (ll i=1;i<=maxn+1;i++)27     {28         sum[i]=sum[i-1]+(f[i].l+f[i].r)*i*(f[i].r-f[i].l+1)/2%P;29         sum[i]%=P;30     }31 }32 int main()33 {34     freopen("nan.in","r",stdin);35     freopen("nan.out","w",stdout);36     pre();37     cin>>t;38     for (int i=1;i<=t;i++){39         ll x,ans=0;40         scanf("%I64d",&x);41         ll li=1,ri=maxn+1;42         while (li<=ri){43             ll mid=(li+ri)>>1;44             if (f[mid].r<x) li=mid+1;45             else ri=mid-1;46         }47         //if (f[ri].r<x) ri+=1;48         ans=sum[ri];49         ans+=(ri+1)*(x+f[ri+1].l)*(x-f[ri].r)/2%P;50         ans%=P;51         printf("%I64d\n",ans);52     }53     return 0;54 }

  明天加油!

【55测试】【字符串】【栈】【找规律】