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; }
正解是线段树维护$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; }
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$。
没什么水平。。。