2019-8-5 考试总结

A. 矩阵游戏

是个水题,但是还是想了很长时间。

每个点对答案的贡献是$A[i][j]\times H[i]\times Z[j]$,

然后这个$sum$就是$\sum A[i][j]\times H[i]\times Z[j]$,

把$H[i]$提出来,也就是$\sum (H[i]\times \sum A[i][j]\times Z[j])$,

这个$A[i][j]$是有规律的,

这一行和上一行的差值就是$m\times \sum Z[j]$,

然后就可以逐行转移了。

最后是$O(n)$的。

丑陋的代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define Maxn 1000050
#define Reg register
#define INF 0x7ffffff
#define int long long
#define mod 1000000007
using namespace std;
int n,m,k,sum=0,ans=0,H[Maxn],Z[Maxn],dp[Maxn];
string s;
signed main()
{
    scanf("%lld%lld%lld",&n,&m,&k);
    for(Reg int i=1;i<=n;++i) H[i]=Z[i]=1;
    for(Reg int i=1;i<=m;++i) H[i]=Z[i]=1;
    for(Reg int i=1,x,y;i<=k;++i)
    {
        cin>>s;
        scanf("%lld%lld",&x,&y);
        if(s[0]=='R') H[x]=(H[x]*y)%mod;
        else Z[x]=(Z[x]*y)%mod;
    }
    for(Reg int i=1;i<=m;++i)
    {
        dp[1]=(dp[1]+i*Z[i]%mod)%mod;
        sum=(sum+Z[i])%mod;
    }
    for(Reg int i=2;i<=n;++i)
        dp[i]=(dp[i-1]+m*sum%mod)%mod;
    for(Reg int i=1;i<=n;++i)
        ans=(ans+H[i]*dp[i]%mod)%mod;
    printf("%lld",ans);
    return 0;
}
View Code

B. 跳房子

C. 优美序列

一开始想的莫队(为啥他们都先想到分治),

想到可以向左右拓展,所以就朝莫队的方向想了。

最后发现,其实莫队还不如直接暴力。

开$2$颗线段树,一个是区间内的编号的最值,一个是一段编号的位置的最值。

每个询问直接找最远的两个值,向左向右拓展。

最后得到$80$分$TLE$。

丑陋的代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define int long long
#define Maxn 100050
#define Reg register
#define INF 0x7ffffff
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
int n,m,ansm,ansn,maxx,minn,A[Maxn],pos[Maxn];
struct Tree {Tree *lch,*rch; int mx,mn;};
Tree *New()
{
    Tree *p=new Tree;
    p->lch=p->rch=NULL;
    p->mx=-INF,p->mn=INF;
    return p;
}
Tree *rot1=New(),*rot2=New();
void up(Tree *p)
{
    p->mx=-INF,p->mn=INF;
    if(p->lch!=NULL)
    {
        p->mx=max(p->lch->mx,p->mx);
        p->mn=min(p->lch->mn,p->mn);
    }
    if(p->rch!=NULL)
    {
        p->mx=max(p->rch->mx,p->mx);
        p->mn=min(p->rch->mn,p->mn);
    }
    return;
}
void build(Tree **p,int l,int r)
{
    if(*p==NULL) *p=New();
    if(l==r)
    {
        (*p)->mx=(*p)->mn=pos[l];
        return;
    }
    int mid=(l+r)>>1;
    if(l<=mid) build(&((*p)->lch),l,mid);
    if(mid+1<=r) build(&((*p)->rch),mid+1,r);
    up(*p);
    return;
}
void bup(Tree **p,int l,int r)
{
    if(*p==NULL) *p=New();
    if(l==r)
    {
        (*p)->mx=(*p)->mn=A[l];
        return;
    }
    int mid=(l+r)>>1;
    if(l<=mid) bup(&((*p)->lch),l,mid);
    if(mid+1<=r) bup(&((*p)->rch),mid+1,r);
    up(*p);
    return;
}
void ask(Tree *p,int l,int r,int sol,int sor)
{
    if(p==NULL||(p->mx<=ansm&&p->mn>=ansn)) return;
    if(sol<=l&&r<=sor)
    {
        ansm=max(ansm,p->mx);
        ansn=min(ansn,p->mn);
        return;
    }
    int mid=(l+r)>>1;
    if(sol<=mid) ask(p->lch,l,mid,sol,sor);
    if(mid+1<=sor) ask(p->rch,mid+1,r,sol,sor);
    return;
}
void query(Tree *p,int l,int r,int sol,int sor)
{
    if(p==NULL||(p->mx<=maxx&&p->mn>=minn)) return;
    if(sol<=l&&r<=sor)
    {
        maxx=max(maxx,p->mx);
        minn=min(minn,p->mn);
        return;
    }
    int mid=(l+r)>>1;
    if(sol<=mid) query(p->lch,l,mid,sol,sor);
    if(mid+1<=sor) query(p->rch,mid+1,r,sol,sor);
    return;
}
signed main()
{
//    freopen("text.in","r",stdin);
    scanf("%lld",&n);
    for(Reg int i=1;i<=n;++i)
    {
        scanf("%lld",&A[i]);
        pos[A[i]]=i;
    }
    build(&rot1,1,n); bup(&rot2,1,n);
    scanf("%lld",&m);
    for(Reg int i=1,l,r;i<=m;++i)
    {
        maxx=-INF,minn=INF;
        scanf("%lld%lld",&l,&r);
        query(rot2,1,n,l,r);
        int ln=l,rn=r;
        while(1)
        {
            if(maxx-minn==rn-ln||(ln==1&&rn==n))
            {
                printf("%lld %lld\n",ln,rn);
                break;
            }
            ansm=-INF,ansn=INF;
            ask(rot1,1,n,minn,maxx);
            ln=ansn,rn=ansm;
            query(rot2,1,n,ln,rn);
        }
    }
    return 0;
}
View Code

总结:

$T1$乍一看没什么思路,

刚开始一直在想怎么用线段树。

不管怎样都是$O(nm)$的复杂度。

然后就弃掉了。

最后码完$T3$有回来看$T1$,想了一会儿。

式子写下来,发现其实很水。逐行转移就可以了。

开始看$T2$,也没什么思路。

码了一个暴力(最后还打错了),先拿到这暴力分再说。

$T3$好像做过的样子,想到那个莫队专题里的$permu$,心态就炸了。

因为我没做那个题。

静下心来好好想,结果码了$2$颗线段树,然后水到$80$分。

最后回去看$T1$和$T2$,$T1$打完确实心态就稳了。

然后$T2$还是炸了,暴力分都没拿到。

所以最后$100+5+80=185$。

没什么水平。。。

猜你喜欢

转载自www.cnblogs.com/Milk-Feng/p/11302189.html
今日推荐