校内模拟赛(20170917)

这套题目也是比较恶心的,。。。。都是奇技淫巧的说。

————————————————我是分割线——————————————————

T1:消消乐(tet)

【题目描述】

有一个2n个数字排成一列,这个数列中由1..n中的数字组成,每个数字都恰好出现两次。每个回合可以交换相邻两个数字,交换以后如果有两个相同的数字相邻,那么将这两个数字消除,并将这两个数字的两端拼起来;如果拼接后的数列仍有相同的数字相邻,那么将引发连锁反应直到没有两个相同数字相邻。现在你想知道最少需要几个回合可以消除所有的数字。

【输入描述】

第一行输入一个n,表示数字范围。

接下来的2n行,每行一个数字,表示第i个位置的数字。

【输出描述】

第一行输出一个数,表示最少需要的回合数w。

接下来的w行,每行输出一个数m[i]。m[i]表示对于第i回合,你的操作为交换当前数列中的第m[i]个数和第(m[i]+1)个数。如果有多种方案,允许输出任意一种。

保证存在不超过的答案。

【样例】


输入


输出


5

5

2

3

1

4

1

4

3

5

2


2

5

2

【数据范围】

对于30%的数据,1<=n<=1000

对于100%的数据,1<=n<=50000

————————————————我是分割线——————————————————

这是一道神奇的题目。

首先我们想一想,如果我们改变移动的顺序,其实答案是不变的,那么我们想一下,如果有四个数:1、4、1、4那么我们需要消除这两组数需要一步,反之,如果变成4、1、1、4,那么就可以消掉了。。

所以我们尝试把数列通过移动变成一个新的数列,满足a[i][0]<a[j][0]&&a[j][1]<a[i][0](i<j)其中a[i][0]表示第i个数第一次出现的位置,a[i][1]表示第i个数第二次出现的位置。

然后我们发现如果一次交换后,可能前面的已经排好的数列又会变化,所以交换后往左走看是否需要继续交换,如果不需要就往右走。走的过程中记一下消掉的数个数。

下面贴代码:

#include<cstdio>
#define MN 200005
using namespace std;
int a[MN],b[MN][2],l[MN],r[MN],Ans[MN<<4],ans,pos=1,n;
void swap(int &x,int &y){x^=y,y^=x,x^=y;}
int main(){
    freopen("tet.in","r",stdin);
    freopen("tet.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=2*n;i++){
        scanf("%d",&a[i]),l[i]=i-1,r[i]=i+1;
        if(b[a[i]][0])b[a[i]][1]=i;
        else b[a[i]][0]=i;
    }r[0]=1;l[n*2+1]=n*2,r[n*2+1]=n*2+1;
    for(int i=1;i<=2*n;){
        if(a[i]==a[r[i]]){
            l[r[r[i]]]=l[i];r[l[i]]=r[r[i]];
            if(!l[i])i=r[r[i]];
            else i=l[i],--pos;
        }else {
            if(b[a[i]][1]<b[a[r[i]]][1]){
                swap(a[i],a[r[i]]);
                Ans[++ans]=pos;
                if(l[i])i=l[i],--pos;
            }else i=r[i],++pos;
        }
    }
    printf("%d\n",ans);
    for(int i=1;i<=ans;i++)printf("%d\n",Ans[i]);
    fclose(stdin);
    fclose(stdout);
}

————————————————我是分割线——————————————————

T2:寻找(find)

【题目描述】

你有一个长度为n个由abc三个字母组成的字符串s,你现在想知道有多少三元组(i,j,k)满足:

1、 s[i]=’a’,s[j]=’b’,s[k]=’c’

2、 j^2=ik

请你求出满足条件的三元组的数量

【输入描述】

第一行为n,表示字符串长度

第二行为一个长度为n的字符串。

【输出描述】

输出一个数, 表示满足条件的三元组的数量。

【样例】


输入


输出


5

abccc


1

【数据范围】

对于30%的数据,n<=500

对于50%的数据,n<=5000

对于70%的数据,n<=10^5

对于100%的数据,1<=n<=5*10^5

————————————————我是分割线——————————————————

这道题显然就是枚举所有的平方数的因数QAQ

然后我们可以利用O(n的质因数个数)的时间用dfs枚举出所有平方数的因数。

然后判断即可,时间复杂度O(nlogn)

下面贴代码

#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
int ans,n,tmp,len;
char ch[500005];
vector <pair<int,int> > V;
void add(int x){
    int t;V.clear();
    for(int i=2;i<=sqrt(x);i++)if(x%i==0){
        t=0;
        while(x%i==0)t+=2,x/=i;
        V.push_back(make_pair(i,t));
    }
    if(x>1)V.push_back(make_pair(x,2));
}
void dfs(int x,long long y){
    if(x>=len){
        if(1ll*tmp*tmp/y<=n&&(ch[y]==‘a‘&&ch[1ll*tmp*tmp/y]==‘c‘||ch[y]==‘c‘&&ch[1ll*tmp*tmp/y]==‘a‘))ans++;
        return;
    }dfs(x+1,y);int i;
    for(i=1;i<=V[x].second;i++){
        y*=V[x].first;
        if(y>=tmp)break;
        dfs(x+1,y);
    }
}
int main(){
    freopen("find.in","r",stdin);
    freopen("find.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){ch[i]=getchar();while(ch[i]<‘a‘||ch[i]>‘c‘)ch[i]=getchar();}
    for(tmp=2;tmp<n;tmp++)if(ch[tmp]==‘b‘){
        add(tmp);
        len=V.size();
        dfs(0,1);
    }
    printf("%d\n",ans);
    fclose(stdin);
    fclose(stdout);
}

————————————————我是分割线——————————————————

T3:大芳的逆行板载(boat)

【题目描述】

大芳有一个不太好的习惯:在车里养青蛙。青蛙在一个n厘米(11n毫米s)的Van♂杆子上跳来跳去。她时常盯着青蛙看,以至于突然逆行不得不开始躲交叉弹。有一天他突发奇想,在杆子上每1厘米为一个单位,瞎涂上了墨水,并且使用mOgic,使青蛙跳过之处墨水浓度增加x。当然,他还会闲着无聊滴几滴墨水再涂♂抹均匀。

他现在无时无刻都想知道,第l厘米到第r厘米墨水的浓度是多少?

哦不!等等,他现在找到了一个计算器,可以输入几个数字与x,计算他们的x次幂和,所以……他想知道的是第l厘米到第r厘米墨水的浓度的x次幂和是多少?

大芳有3种舰长技能骚操作:

1、续:把青蛙放到第l厘米处,戳青蛙使其跳至r。效果:第l厘米至第r厘米墨水浓度增加x

2、抚♂摸:擦干杆子某一部分,重新滴加墨水并抹匀。效果:使第l厘米至第r厘米墨水浓度都变成x

最后一种是:

3、压线逆行,将车流看做⑨弹幕找安定点,掏出计算器,大喊板载后计算:

第l厘米至第r厘米墨水浓度的x次幂和是几何?记得答案要模1000000007

【输入描述】

第一行n和m,表示杆子长n厘米,大芳要进行m次骚操作。

第二行n个数字,表示初始墨水浓度。第i个数字为第i厘米墨水浓度

接下来每行4个数字,依次为:操作编号(1、2或3)l,r,x

【输出描述】

每次进行3操作,输出一行表示答案

记得膜模1000000007

【样例】


输入


输出


5 5

19844 14611 26475 4488 6967

2 1 3 15627

2 1 2 30113

2 3 5 14686

2 5 5 32623

3 1 2 8


466266421

【数据范围】

k表示询问的幂的大小,也就是操作3对应的x。

对于20%的数据,满足n,m<=1000

对于另外20%的数据,满足k<=1

对于另外20%的数据,满足k<=2

对于另外20%的数据,满足n,m<=50000

对于100%的数据,满足n,m<=100000,0<=k<=10

操作1,2对应的x<=10^9+7

————————————————我是分割线——————————————————

这是本次考试最恶心的一题。显然,我们知道这是线段树。。

因为不同的幂数之间的答案不互相影响。所以我们考虑建11棵线段树。

每一棵线段树如何更新?我们考虑利用杨辉三角公式更新。。。然后用两个tag分别维护修改和添加。

然后。。。。就炸了!因为贼难写!!!!

看看就知道了

#include<cstdio>
#define MN 100005
using namespace std;
const int mod=1000000007;
int n,m;
struct tree{
    long long sum[11];
}tr[MN<<3];
long long a[MN],tag[MN<<3],tag2[MN<<3],xishu[100][100];
void build(int l,int r,int k){
    tr[k].sum[0]=1;tag[k]=-1;
    if(l==r){
        tr[k].sum[1]=a[l];
        for(int i=2;i<=10;i++)tr[k].sum[i]=(tr[k].sum[i-1]*a[l])%mod;return;
    }int mid=l+r>>1;
    build(l,mid,k<<1),build(mid+1,r,k<<1|1);
    for(int i=0;i<=10;i++)tr[k].sum[i]=(tr[k<<1].sum[i]+tr[k<<1|1].sum[i])%mod;
}
void pushdown(int l,int r,int k){
    if(tag[k]!=-1){
        long long len=r-l+1;
        tag[k<<1]=tag[k<<1|1]=tag[k];
        tr[k<<1].sum[1]=tag[k]*(len-(len>>1))%mod;tr[k<<1|1].sum[1]=tag[k]*(len>>1)%mod;tag2[k<<1]=tag2[k<<1|1]=0;
        for(int i=2;i<=10;i++)tr[k<<1].sum[i]=(tr[k<<1].sum[i-1]*tag[k])%mod,tr[k<<1|1].sum[i]=(tr[k<<1|1].sum[i-1]*tag[k])%mod;tag[k]=-1;
    }
    if(tag2[k]){
        tag2[k<<1]=(tag2[k<<1]+tag2[k])%mod;
        tag2[k<<1|1]=(tag2[k<<1|1]+tag2[k])%mod;
        long long len=r-l+1,tmp1[11],tmp2[11];
        for(int i=1;i<=10;i++){
            tmp1[i]=tr[k<<1].sum[i],tmp2[i]=tr[k<<1|1].sum[i];long long now=tag2[k];
            for(int j=2;j<=i;j++){
                tmp1[i]=(tmp1[i]+(xishu[i][j]*now)%mod*tr[k<<1].sum[i+1-j]%mod)%mod;
                tmp2[i]=(tmp2[i]+(xishu[i][j]*now)%mod*tr[k<<1|1].sum[i+1-j]%mod)%mod;
                now=now*tag2[k]%mod;
            }tmp1[i]=(tmp1[i]+now*(len-(len>>1))%mod)%mod,tmp2[i]=(tmp2[i]+now*(len>>1)%mod)%mod;
        }
        for(int i=1;i<=10;i++)tr[k<<1].sum[i]=tmp1[i],tr[k<<1|1].sum[i]=tmp2[i];
        tag2[k]=0;
    }
}
void update(int l,int r,int a,int b,int k,int kind,int ad){
    if(a<=l&&r<=b){
        if(kind==1){
            tag2[k]=0;tag[k]=ad;tr[k].sum[1]=1ll*ad*(r-l+1)%mod;
            for(int i=2;i<=10;i++)tr[k].sum[i]=tr[k].sum[i-1]*ad%mod;
            return ;
        }else {
            long long tmp[11];
            tag2[k]=(tag2[k]+ad)%mod;
            long long len=r-l+1;
            for(int i=1;i<=10;i++){
                tmp[i]=tr[k].sum[i];
                long long now=ad;
                for(int j=2;j<=i;j++){
                    tmp[i]=(tmp[i]+xishu[i][j]*now%mod*tr[k].sum[i+1-j]%mod)%mod;
                    now=(now*ad)%mod;
                }tmp[i]=(tmp[i]+now*len)%mod;
            }
            for(int i=1;i<=10;i++)tr[k].sum[i]=tmp[i];
        }return;
    }if(tag[k]!=-1||tag2[k])pushdown(l,r,k);
    int mid=l+r>>1;
    if(a<=mid)update(l,mid,a,b,k<<1,kind,ad);
    if(b>mid)update(mid+1,r,a,b,k<<1|1,kind,ad);
    for(int i=1;i<=10;i++)tr[k].sum[i]=(tr[k<<1].sum[i]+tr[k<<1|1].sum[i])%mod;
}
long long query(int l,int r,int a,int b,int k,int tt){
    if(l==a&&r==b)return tr[k].sum[tt];if(tag[k]!=-1||tag2[k])pushdown(l,r,k);
    int mid=l+r>>1;
    if(b<=mid)return query(l,mid,a,b,k<<1,tt);
    if(a>mid)return query(mid+1,r,a,b,k<<1|1,tt);
    return (query(l,mid,a,mid,k<<1,tt)+query(mid+1,r,mid+1,b,k<<1|1,tt))%mod;
}
int main(){
    freopen("boat.in","r",stdin);
    freopen("boat.out","w",stdout);
    scanf("%d%d",&n,&m);
    int opt,x,y,z;
    for(int i=1;i<=10;i++)xishu[i][1]=xishu[i][i+1]=1;
    for(int i=2;i<=10;i++)for(int j=2;j<=i;j++)xishu[i][j]=xishu[i-1][j-1]+xishu[i-1][j];
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    build(1,n,1);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&opt,&x,&y,&z);
        if(opt==1)update(1,n,x,y,1,2,z%mod);
        else if(opt==2)update(1,n,x,y,1,1,z%mod);
        else printf("%lld\n",query(1,n,x,y,1,z));
    }
    fclose(stdin);
    fclose(stdout);
}
时间: 2024-10-09 23:46:32

校内模拟赛(20170917)的相关文章

2017.6.11 校内模拟赛

题面及数据及std(有本人的也有原来的) :2017.6.11 校内模拟赛 T1 自己在纸上模拟一下后就会发现 可以用栈来搞一搞事情 受了上次zsq 讲的双栈排序的启发.. 具体就是将原盘子大小copy一下排个序 用两个指针维护两个数组(原数据 和 排序后的数据), 即分为1数据和2数组 将小于1指针指向的数据的2数组中的数据全部压入栈中 后进行消除, 将栈栈顶元素与当前1数组中的1指针指向的元素进行比较 相同则消除 后重复过程 直至指针超过N 后判断一下是否两个指针都超过了N... #incl

校内模拟赛 Zbq&#39;s Music Challenge

Zbq's Music Challenge 题意: 一个长度为n的序列,每个位置可能是1或者0,1的概率是$p_i$.对于一个序列$S$,它的得分是 $$BasicScore=A\times \sum_{i=1}^{n}{S_i} \tag{1}$$ $$ combo(i)=\left\{ \begin{aligned} &S_i & &i=1 \\ &combo(i-1)+1 & &i\neq 1 ~\mathrm{and}~ S_i=1 \\ &

[20180816]校内模拟赛

T1 清理(clear) 问题描述 小 C 最近自己开发了一款云盘软件,目前已有??个用户.小C 的云盘上的文件会被后台分成两种类型,活动 文件和非活动文件,活动文件即可能常用的文件,会被放在高速服务器上给用户提供高速下载服务.用户 上传一个文件时,这个文件会被设置为活动文件.由于高速服务器内存大小有限,小 C 需要把一些文件 设为非活动文件,有以下两种设置方式:1.把上传时间前??早的文件全部设为非活动文件:2.把第??个用户上 传的文件全部设为非活动文件.注意这两种方式操作的对象都是所有文件

校内模拟赛T1大美江湖

这就是一个模拟题,注意1234分别对应左右上下横坐标和纵坐标的判断就好了 题解: 需要注意的是,向上取整ceil函数是对于一个double值返回一个double值,也就是说在ceil里面的类型一定要是double,否则会炸 代码: #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<cstring> #include<string>

校内模拟赛:确定小组

  [问题描述] 有n个人坐成一排,这n个人都在某一个小组中,同一个小组的所有人所坐的位置一定是连续的. 有一个记者在现场进行采访,他每次采访都会询问一个人其所在的小组有多少人,被询问的每个人都给出了正确的答案,但是由于时间仓促,记者不一定询问了每个人,我们记录一个长度为n的答案序列,序列的第i个数表示第i个人的回答,如果为0则表示记者没有询问过这个人. 记者发现,对于一些情况,他可以唯一确定这排所有人的分组,而对于另外一些情况则不能,于是记者开始好奇,对于某一个答案序列,他能不能做到这一点,如

校内模拟赛20170604

香蕉锤--双向链表 #include<iostream> #include<cstdio> using namespace std; inline int read(){ int num=0,t=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();} ret

5.13 校内模拟赛

... 果然是dalao们做难题做多了后 简单题水不起来了吗.. 5.13解题报告 300分 T1写了差不多30~40分钟 T2写了不到5min (当时怀疑有坑..) T3推了大概1个多小时的式子, 然后又加上调试差不多一个半小时 时间分配就这样..感觉T2出的太过简单了..直接是个模板 T1 并查集 + 乱搞 T2 快速幂模板 T3 Dp T1 : codevs 2796 最小完全图 二次联通门 : codevs 2796 最小完全图 /* codevs 2796 最小完全图 并查集 + 乱搞

校内模拟赛(20170924)

四校很丧,但是学长的题目更简单 lrb学长的题目为什么都要倒着切,不懂QAQ ----------------我是分割线---------------- T1:个人卫生综合征 每天BBS都要从家里经过城市中的一段路到学校刷五三.城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口ai.bi且有一定的时间花费vi.BBS家编号为1,学校编号为n.今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0.现在他问你改变道路长度之后他到学校

校内模拟赛(20170921)

救命啊,救命啊!学长出丧题啦!!! 学长他们压榨我们的劳动力,然后带着我们的成绩跑了,无奈的我们只好玩命的调程序,把学长留给我们的丧题做完(划掉) 65分的rank 1跑路. ----------------我是分割线---------------- T1:粉饰(decorate) [题目描述] 小D有一块被分为n*m个格子的矩形鱼片.为了装饰鱼片,小D决定给每个格子上色.由于小D很喜欢红白,所以小D给每个格子涂上了红色或白色,第i行第j列的格子颜色记为c[i,j].涂完之后,小D想评估这块鱼片