2019-8-1 考试总结

A. string

刷题时没刷到那个名叫排序的题目,

没思路,然后就$sort$了,$TLE40$。

$emmm……$,刷题太慢。

考试暴力程序:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define Maxn 100050
#define Reg register
using namespace std;
int n,m,R[Maxn],stack[Maxn],vis[Maxn];
char A[Maxn];
struct Node {int tim,x,l,r;} Q[Maxn];
bool comp1(char x,char y) {return x<y;}
bool comp2(char x,char y) {return x>y;}
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s",A+1);
    for(Reg int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&Q[i].l,&Q[i].r,&Q[i].x);
        vis[i]=1;
    }
    if(n<=1000&&m<=1000)
    {
        for(Reg int i=1;i<=m;++i)
        {
            if(Q[i+1].l<=Q[i].l&&Q[i+1].r>=Q[i].r) continue;
            if(Q[i].x==1) sort(A+Q[i].l,A+Q[i].r+1,comp1);
            else sort(A+Q[i].l,A+Q[i].r+1,comp2);
        }
    }
    else
    {
        for(Reg int i=1;i<=m;++i)
        {
            if(!vis[i]) continue;
            Reg int ok=1,top=0;
            for(Reg int j=i+1;j<=m;++j)
            {
                if(Q[j].l<=Q[i].l&&Q[j].r>=Q[i].r) {ok=0; break;}
                if(Q[j].l>=Q[i].l&&Q[j].r<=Q[i].r) stack[++top]=j;
            }
            if(!ok)
            {
                for(Reg int j=1;j<=top;++j) vis[stack[j]]=0;
                continue;
            }
            if(Q[i].x==1) sort(A+Q[i].l,A+Q[i].r+1,comp1);
            else sort(A+Q[i].l,A+Q[i].r+1,comp2);
        }
    }
    for(Reg int i=1;i<=n;++i) printf("%c",A[i]);
    return 0;
}
View Code

正解是线段树维护$26$个字母的区间出现次数,

修改时用桶排,先询问区间内$26$个字母的出现次数,

然后依次区间赋值。

一开始一直$TLE50$,然后改了一点:

if(root==NULL||!root->val) return;

然后就剪枝了。

正解:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define Maxn 100050
#define Reg register
using namespace std;
int n,m,ans,tong[30],num[Maxn];
char S[Maxn];
struct Tree {Tree *lch,*rch; int val,flag;};
Tree *root[30];
inline Tree *New()
{
    Tree *p=new Tree;
    p->lch=p->rch=NULL;
    p->flag=-1;
    return p;
}
inline void down(Tree *root,Reg int l,Reg int r)
{
    if(root->flag==-1||l==r) return;
    if(root->flag==1)
    {
        if(root->lch==NULL) root->lch=New();
        if(root->rch==NULL) root->rch=New();
    }
    Reg int mid=(l+r)>>1,p=root->flag;
    if(l<=mid&&root->lch!=NULL)
    {
        root->lch->val=(mid-l+1)*root->flag;
        root->lch->flag=p;
    }
    if(mid+1<=r&&root->rch!=NULL)
    {
        root->rch->val=(r-(mid+1)+1)*root->flag;
        root->rch->flag=p;
    }
    root->flag=-1;
    return;
}
inline void change(Tree *root,Reg int l,Reg int r,Reg int sol,Reg int sor,Reg int num)
{
    if(root==NULL) return;
    if(l>=sol&&r<=sor)
    {
        root->val=(r-l+1)*num;
        root->flag=num;
        return;
    }
    if(root->flag!=-1) down(root,l,r);
    Reg int mid=(l+r)>>1;
    if(sol<=mid)
    {
        if(num==1&&root->lch==NULL) root->lch=New();
        change(root->lch,l,mid,sol,sor,num);
    }
    if(mid+1<=sor)
    {
        if(num==1&&root->rch==NULL) root->rch=New();
        change(root->rch,mid+1,r,sol,sor,num);
    }
    root->val=0;
    if(root->lch!=NULL) root->val+=root->lch->val;
    if(root->rch!=NULL) root->val+=root->rch->val;
    return;
}
inline void ask(Tree *root,Reg int l,Reg int r,Reg int sol,Reg int sor)
{
    if(root==NULL||!root->val) return;
    if(l>=sol&&r<=sor)
    {
        ans+=root->val;
        root->val=0;
        root->flag=0;
        return;
    }
    if(root->flag!=-1) down(root,l,r);
    Reg int mid=(l+r)>>1;
    if(sol<=mid) ask(root->lch,l,mid,sol,sor);
    if(mid+1<=sor) ask(root->rch,mid+1,r,sol,sor);
    root->val=0;
    if(root->lch!=NULL) root->val+=root->lch->val;
    if(root->rch!=NULL) root->val+=root->rch->val;
    return;
}
inline void dfs(Tree *root,Reg int k,Reg int l,Reg int r)
{
    if(root==NULL||!root->val) return;
    if(l==r)
    {
        if(root->val) num[l]=k;
        return;
    }
    if(root->flag!=-1) down(root,l,r);
    Reg int mid=(l+r)>>1;
    if(l<=mid) dfs(root->lch,k,l,mid);
    if(mid+1<=r) dfs(root->rch,k,mid+1,r);
    return;
}
inline void work(int k,int l,int r)
{
    for(Reg int i=1;i<=26;++i)
    {
        if(root[i]==NULL) continue;
        ans=0; ask(root[i],1,n,l,r);
        tong[i]=ans;
    }
    if(k==1) for(Reg int i=1;i<=26;++i)
    {
        if(!tong[i]||root[i]==NULL) continue;
        r=l+tong[i]-1;
        change(root[i],1,n,l,r,1);
        l=r+1;
    }
    else for(Reg int i=26;i>=1;--i)
    {
        if(!tong[i]||root[i]==NULL) continue;
        r=l+tong[i]-1;
        change(root[i],1,n,l,r,1);
        l=r+1;
    }
    return;
}
int main()
{
    scanf("%d%d%s",&n,&m,S+1);
    for(Reg int i=1,x;i<=n;++i)
    {
        x=S[i]-'a'+1;
        if(root[x]==NULL) root[x]=New();
        change(root[x],1,n,i,i,1);
    }
    for(Reg int i=1,l,r,x;i<=m;++i)
    {
        scanf("%d%d%d",&l,&r,&x);
        work(x,l,r);
    }
    for(Reg int i=1;i<=26;++i) dfs(root[i],i,1,n);
    for(Reg int i=1;i<=n;++i) putchar(num[i]+'a'-1);
    return 0;
}
View Code

B. matrix

一个神$dp$。

直接$Lrefiain$大神博客 传送门

C. big

 一颗$Trie$树,

题目给的变化是循环左移,

把一个数左移,最高位补到最低位。

要从最高位向最低位建树。

至于为什么:

每次模拟的应该是对手的操作。

对手肯定会选择最优策略,

如果从最高位向最低位建树,那么对手每次选择的肯定是最优策略。

否则不一定是对手的最优策略。

可以画一个图。

比如$000$、$010$、$111$。

总结:

这次考试题比较难,然后就。。

还是有厉害的,每道题都有人当场$AC$,

$T1$没思路,直接用$sort$暴力,拿到$40$分,

$T2$有点恶心,题目都没说清楚,

又是手模样例,然后模不过。

幸好最后还是理解了题目,最后直接打了一个状压,得分$20$分,

$T3$当场$CE$,这个$pow$居然在$c++11$中是保留字。

考后用$c++$编译了一遍,发现它没有$CE$,

今天终于发现了$c++$和$c++11$的区别,记住以后别写保留字。。

$T3$期望得分$40$分,实际爆$0$。

最后$40+20+0=60$。

$T3CE$爆零直接从$rank7$掉到$rank42$。

没什么水平。。。

posted @ 2019-08-01 20:56  Milk_Feng  阅读(113)  评论(0编辑  收藏  举报