2016.11.1第56套训练题

hao
【问题描述】
祖玛是一款曾经风靡全球的游戏,其玩法:在条轨道上初始排列着若干个彩色珠子,其中任意三相邻的不会完全同。轨道上并加入原有序列中。一旦三个或更多同色的珠子变成相邻,它们就会立 轨道上并加入原有序列中。
这类除现象可能会连锁式发生,其间你将暂时不射珠子开发商最近准备为玩家写一个游戏过程的回放工具。他们已经在内完成 开发商最近准备为玩家写一个游戏过程的回放工具。他们已经在内完成 了过程记录的功能,而回放实现则委托你来完成。
【输入格式】
第一行是个由大写字母 'A'~'Z' 组成的字符串, 表示轨道上初始珠子序列组成的字符串, 表示轨道上初始珠子序列不同的字母表示颜色。
第二行是一个数字 ?,表示整个回放过程共有 ?次操作。
接下来的 ?行依次对应于各操作。每由一个数字 行依次对应于各操作。每由一个数字 ?和一个大写字母 ?描述, 以空格分隔。其中描述, 以空格分隔。其中描述, 以空格分隔。其中描述, 以空格分隔。其中?为新珠子的颜色。若插入前共有 为新珠子的颜色。若插入前共有 ?颗珠子,则 颗珠子,则 ?∈[0,?]表示新珠子嵌入之后(尚未发生消除前)在轨道上的位序。
【输出格式】
输出共 ?行,依次给出各操作(及可能随即发生的消除现象)之后轨道上 行,依次给出各操作(及可能随即发生的消除现象)之后轨道上 行,依次给出各操作(及可能随即发生的消除现象)之后轨道上 行,依次给出各操作(及可能随即发生的消除现象)之后轨道上
的珠子序列。
如果轨道上已没有珠子,则以 “-”表示 。
【样例输入】
ACCBA
5
1 B
0 A
2 B
4 C
0 A
【样例输出】
ABCCBA
AABCCBA
AABBCCBA
-
A
【数据规模与约定】
100%的数据满足 1≤?≤103,1≤?≤2×103。

题解:

改了半天发现数据还是错的,GG。啊,这道题并不太难,主要就是如何高效的插入和清除。在这里我个人觉得链表最为快捷,当然也可以用数组,只不过,链表的话删除和插入更为简单,不过写错了就GG了。哦对了,链表设置了边界的话,可以不用考虑一开始就是空的情况。

程序:

#include<iostream>//链表存储 注意边界0 
#include<cstdio>
using namespace std;
int n,m,tot=2,fail,k,next[3005],head[3005];
char a[3005],addtion;
void clea(int pos)
{
    int st=pos,en=pos,num=1;
    while(st!=0&&a[head[st]]==a[st]) st=head[st],num++;
    while(en!=fail&&a[next[en]]==a[en]) en=next[en],num++;
    if(num>=3)
    {
        st=head[st],en=next[en];
        head[en]=st,next[st]=en;
        clea(st);
    }
    return ;
}
void work(int tm,char col)
{
    tot++;
    int pos=0;
    for(int i=1;i<=tm+1;i++) pos=next[pos];
    a[tot]=col;
    head[tot]=head[pos];
    head[pos]=tot;
    next[tot]=next[head[tot]];
    next[head[tot]]=tot;
    clea(tot);
}
void prin()
{
    if(next[0]!=fail)
    {
        int q=next[0];
        while(q!=fail)
        {
            cout<<a[q];
            q=next[q];
        }
        cout<<endl;
        return ;
    }
    cout<<'-'<<endl;
}
int main()
{
    freopen("hao.in","r",stdin);
    freopen("hao.out","w",stdout);
    a[0]=1;
    a[1]=getchar();
    while(a[tot-1]<='Z'&&a[tot-1]>='A') a[tot]=getchar(),tot++;
    a[--tot]=2;
    for(int i=1;i<tot;i++) next[i]=i+1,head[i]=i-1;
    next[0]=1,head[tot]=tot-1;
    fail=tot;
    //head[0]=-1;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>k>>addtion;
        work(k,addtion);
        prin();
        if(i==41) cout<<"             "<<endl;
    }
    return 0;
}

 

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行。
第一行包含个整数 ?,表示入栈序列长度。
第二行包含 ?个整数,表示入栈序列。输据保证给定的是 1到 n的 全排列,即不会出现重复数字。
【输出格式】
仅一行,共 ?个整数,表示你计算出的栈序列。
【样例输入】
3
2 1 3
【样例输出】
3 1 2
【数据规模与约定】
对于 30%的数据 ,1≤?≤103。
对于 60%的数据 ,1≤?≤105。
对于 100%的数据 ,1≤?≤106。

题解:

第二题啊,水啊,就是个找最大的玩意儿。因为最后输出的总长不变,想要字典序最大,那第一个必须是最大的。这样的话,数组就分为两部分,一部分是排在最大值前面,所以已经在栈中,而另一部分还没有进栈。那么问题就转化为了栈顶元素与未进栈元素最大值的比较。come to easy。然而GG了20,因为当时在比较栈顶元素与未进站元素最大值比较时有点问题,狭隘了,后来改过来就对了。嗨呀,气哦。

#include<iostream>
#include<cstdio>
#include<algorithm >
#define MN 1000005
using namespace std;
struct stu{
	int w,x,s;
}a[MN],ans[MN];
int tot=1,n;
bool f[MN];
bool cmp1(const stu & q1,const stu & q2)
{
	return q1.w>q2.w;
}
bool cmp2(const stu & q1,const stu & q2)
{
	return q1.x<q2.x;
}
int main()
{
	freopen("kun.in","r",stdin);
	freopen("kun.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) 
	{scanf("%d",&a[i].w); a[i].x=i;}
	sort(a+1,a+n+1,cmp1);
	for(int i=1;i<=n;i++) a[i].s=i;
	sort(a+1,a+n+1,cmp2);
	for(int i=1;i<=n;i++)
	{
		if(tot==a[i].s) cout<<a[i].w<<' ';
		else ans[0].w++,ans[ans[0].w].w=a[i].w,ans[ans[0].w].s=a[i].s;
		f[a[i].s]=true;
		while(f[tot])	tot++;
		while(tot>=ans[ans[0].w].s&&ans[0].w>0)
		{
				cout<<ans[ans[0].w].w<<' '; 
				ans[0].w--;
		}
	}
	while(ans[0].w)
	{
		cout<<ans[ans[0].w].w<<' ';
		ans[0].w--;
	}
	return 0;
}

  

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,…。
如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 ?最后出现的位置为 最后出现的位置为 最后出现的位置为 最后出现的位置为 最后出现的位置为 最后出现的位置为 最后出现的位置为 最后出现的位置为 ????(?), 那么现在我希望知道 那么现在我希望知道 那么现在我希望知道 那么现在我希望知道 那么现在我希望知道 那么现在我希望知道 那么现在我希望知道 那么现在我希望知道 那么现在我希望知道 ????(????(?))等于多少 。
【输入格式】
第一行 一个整数 ?,代表数 据组。
接下来 ?行每行一个整数 ?。
【输出格式】
?行,每行一个整数 ,代表 ????(????(?)) mod (109+7)的值 。
【样例输入】
3
3
10
100000
【样例输出】
11
217
507231491
【数据规模与约定】
对于 30%的数据, 1≤?≤103。
对于 60%的数据 ,1≤?≤106。
对于 100%的数据 ,1≤?≤109,1≤?≤2×103。

题解:

第三题,本质在于找规律,并且需要简化规律。本题就是找到规律后,差分分块,然饿,自己做的时候并没有简化到差分,只得了暴力的一点分数。蓝瘦,香菇,然后下午改了两个小时,最后发现自己理解的分块和大神说的不一样,GG。简直整个人都不好了。于是推翻了重新来,总算过了。简述一下,就是last[i]时i来源,那么last[i]与last[last[i]]可以得到一个相同块数的数字数量进而得知其位置,说白了,出现位置就是前面所有数字的数量和。所以说需要在这些数量和之间注意规律。那么由题意我们可以知道,这个数列时122334445556666777788889999910101010101111111111.....得到一个位置的数列是1,3,5,8,11,15,19,23,28,33....那么公式就出来了,程序也就简单了(嗨呀,没时间详写了)

#include<iostream>//sum
#include<cstdio>
#include<algorithm>
#define p 1000000007
#define ll long long
#define MN 1400005
using namespace std;
int T,com[MN],sum[MN],comsum[MN],tot=3;
ll ans;
int x;
void inint()
{
    com[1]=1,com[2]=2,com[3]=2;
    int tail=4;
    int i=3,j=1;
    while(tail<=1400000)
    {
        if(j>com[i]) j=1,i++;
        com[tail]=i,tail++,j++;
    }
    ll last=0;
    for(i=1;i<=1400000;i++) 
    {
        ll l=last+1;
        ll r=last+com[i];
        sum[i]=(sum[i-1]+(ll)com[i]*(l+r)/2%p*i%p)%p;
        comsum[i]=com[i]+comsum[i-1];//sum
        last=r;
    }
}
ll getlast(int we)
{
    ll pos;
    int num;
    int i = upper_bound(comsum+1,comsum+1400001,we) - comsum - 1;
    pos=sum[i];
    if(comsum[i]<we)
    {
        pos=sum[i],num=comsum[i];
        int len=we-num;
        pos=(pos+((ll)len*(num+1+num+len)/2%p)*(i+1)%p)%p;
    }
    return pos;
}
int main()
{
    freopen("nan.in","r",stdin);
    freopen("nan.out","w",stdout);
    scanf("%d",&T);
    inint();    
    for(int i=1;i<=T;i++)
    {
        scanf("%d",&x);
        ans=getlast(x);
        cout<<ans<<endl;
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/fisch/p/6021189.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值