20191011

前言

  • 最近考试考得最差的一次吧。
  • 考试的时候太浮躁了,T2题都读错。
  • 其实读错题没什么,主要是T1连对拍都不打,于是一些非常智障的错误导致本应AC的代码变成WA0。
  • 以后考试有时间的话对拍还是尽量题题都打……

T1

  • 这场考试也挺奇怪的,我感觉T1应该是三个题里最难的。
  • 考试的时候刚开始一直觉得直接快速幂就行,但后来发现需要考虑行间关系,便很自然的想到正解。
  • 可以把%n后结果相同的列一起考虑,这样可以进行dp
  • 设f[i][j]表示考虑了%n结果不大于i的所有列,一共放了j个棋子的方案数。
  • 则$f[i][j]=\sum\limits_{k=max(0,j-n)}^j f[i-1][j-k]*{{C_n^k}^{m/n+[m\%n>=i]}}$
  • 显然可以滚动。
  • 然后我就滚动不清空,爆零两行泪了……
  • ${C_n^k}^{m/n+[m\%n>=i]}$这个东西可以预处理的。
  • 所以时间复杂度为$\Theta(N^4)$,空间复杂度$\Theta(N^2)$。
  • 注意有(应该有,我不确定)m<n的情况。
#include<cstdio>
using namespace std;
int const N=10002,M=102,mod=1e9+7;
long long fac[N],inv[N];
long long cp[M];
long long f[2][N];
int cf[M];
long long cq[M][2];
inline long long power(long long x,long long y){
    long long ans=1;
    for(;y;y>>=1,x=x*x%mod)
        if(y&1)ans=ans*x%mod;
    return ans;
}
inline long long C(int x,int y){
    return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
inline int max(int x,int y){
    return x>y?x:y;
}
int main(){
    //freopen("3.in","r",stdin);
    //freopen("6.out","w",stdout);
    int n,c;
    long long m;
    scanf("%d%lld%d",&n,&m,&c);
    int lit=n*n,hh=m%n,pc=(m/n)%(mod-1);
    fac[0]=1;
    for(register int i=1;i<=lit;++i)fac[i]=fac[i-1]*i%mod;
    inv[lit]=power(fac[lit],mod-2);
    for(register int i=lit;i;--i)inv[i-1]=inv[i]*i%mod;
    for(register int i=0;i<=n;++i)cp[i]=C(n,i);
    for(register int i=1;i<=hh;++i)cf[i]=1;
    for(register int i=0;i<=n;++i)
        cq[i][0]=power(cp[i],pc),cq[i][1]=cq[i][0]*cp[i]%mod;
    int u=0,v=1;
    f[0][0]=1;
    if(m<n){
        for(register int i=1;i<=m;++i,u=v,v^=1)
            for(register int j=0;j<=c;++j){
                f[v][j]=0;
                for(register int k=max(0,j-n);k<=j;++k)
                    f[v][j]=(f[v][j]+cq[j-k][1]*f[u][k])%mod;
            }
        printf("%lld",f[u][c]);
        return 0;
    }
    for(register int i=1;i<=n;++i,u=v,v^=1)
        for(register int j=0;j<=c;++j){
            f[v][j]=0;
            for(register int k=max(0,j-n);k<=j;++k)
                f[v][j]=(f[v][j]+cq[j-k][cf[i]]*f[u][k])%mod;
        }
    printf("%lld",f[u][c]);
    return 0;
}
View Code

T2

  • 考试看成最长不下降子串,当场去世……
  • 题意是只要左端点最小右端点最大就行,中间元素可不单调。
  • 考虑从右向左扫描,维护一个单调不上升的栈。
  • 把栈内元素当作右端点,维护栈内元素的左端点即可。
  • 具体实现不是很好描述,请自行脑补(不行就颓码吧)。
  • 时空复杂度$\Theta(N)$
  • 本题1e7的读入量,使用fread可以快3倍以上。
#include<cstdio>
#define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,L,stdin),S==T))?EOF:*S++)
using namespace std;
int const N=1e7+5,L=2e8;
char buf[L],*S,*T;
inline int read(){
    int ss(0);char bb(getchar());
    while(bb<48||bb>57)bb=getchar();
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss;
}
inline int max(int x,int y){
    return x>y?x:y;
}
inline int min(int x,int y){
    return x<y?x:y;
}
int a[N],stk[N],mx[N],top,ans=1;
int pos[N];
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    int n=read();
    a[0]=1e9+7;
    for(register int i=1;i<=n;++i)a[i]=read();
    for(register int i=n,x;i;--i){
        x=a[i];
        while(x>a[stk[top]]){
            ans=max(ans,stk[top]-pos[top]+1);
            if(top^1 && mx[top-1]>=a[pos[top]])pos[top-1]=pos[top];
            mx[top-1]=min(mx[top-1],mx[top]),--top;
        }
        stk[++top]=i;
        pos[top]=i,mx[top]=a[i];
    }
    while(a[0]>a[stk[top]]){
        ans=max(ans,stk[top]-pos[top]+1);
        if(top^1 && mx[top-1]>=a[pos[top]])pos[top-1]=pos[top];
        mx[top-1]=min(mx[top-1],mx[top]),--top;
    }
    printf("%d",ans);
    return 0;
}
/*5
3 8 7 5 9  
*/
View Code

T3

  • 没什么好说的,原题,同permu。
  • 才知道当时打的是回滚莫队……当时颓的题解也没说啊
  • 时间复杂度$\Theta(N\sqrt{N})$,空间复杂度$\Theta(N)$。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int const N=1e5+5;
inline int read(){
    int ss(0);char bb(getchar());
    while(bb<48||bb>57)bb=getchar();
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss;
}
inline int max(int x,int y){
    return x>y?x:y;
}
int n,m;
int a[N],stk[N],top;
int as[N];
struct node{
    int l,r,id;
}q[N];
int bl[N],rb[N];
int bar[N],le[N],re[N];
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read(),m=read();
    int bk=sqrt(n),ct=n/bk,ln=0,rn=0;
    for(register int i=1;i<=ct;++i){
        ln=rn+1,rn+=bk;
        rb[i]=rn;
        for(register int j=ln;j<=rn;++j)bl[j]=i;
    }
    if(rn<n){
        rb[++ct]=n;
        for(register int j=rn+1;j<=n;++j)bl[j]=ct;
    }
    for(register int i=1;i<=n;++i)a[i]=read();
    for(register int i=1;i<=m;++i)q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q+1,q+m+1,[](node skyh,node yxs){
        return (bl[skyh.l]^bl[yxs.l])?skyh.l<yxs.l:skyh.r<yxs.r;
    });
    for(register int i=1,ans,tans,z;i<=m;++i){
        if(bl[q[i].l]^bl[q[i-1].l]){
            memset(bar,0,sizeof(bar));
            memset(le,0,sizeof(le));
            memset(re,0,sizeof(re));
            rn=rb[bl[q[i].l]];
            ans=tans=0;
        }
        //printf("%d %d %d\n",q[i].l,q[i].r,rb[bl[q[i].l]]);
        if(q[i].r<=rb[bl[q[i].l]]){
            for(register int j=q[i].r;j>=q[i].l;--j){
                ++bar[stk[++top]=z=a[j]];
                if(bar[z-1]&&bar[z+1])
                    le[re[le[z-1]]=re[z]=re[z+1]]=le[z]=le[z-1];
                else if(bar[z-1])re[le[z]=le[z-1]]=re[z]=z;
                else if(bar[z+1])le[re[z]=re[z+1]]=le[z]=z;
                else le[z]=re[z]=z;
                tans=max(tans,re[z]-le[z]+1);
            }
            while(top){
                z=stk[top--];
                if(le[z]^z)re[le[z]]=z-1;
                if(re[z]^z)le[re[z]]=z+1;
                le[z]=re[z]=0,--bar[z];
            }
            as[q[i].id]=tans,tans=0;
            continue;
        }
        //printf("%d ",rn);
        while(rn<q[i].r){
            ++bar[z=a[++rn]];
            if(bar[z-1]&&bar[z+1])
                le[re[le[z-1]]=re[z]=re[z+1]]=le[z]=le[z-1];
            else if(bar[z-1])re[le[z]=le[z-1]]=re[z]=z;
            else if(bar[z+1])le[re[z]=re[z+1]]=le[z]=z;
            else le[z]=re[z]=z;
            ans=max(ans,re[z]-le[z]+1);
            //printf("!!%d %d %d %d\n",ans,z,re[z],le[z]);
        }//printf("%d\n",ans);
        tans=ans;
        for(register int j=rb[bl[q[i].l]];j>=q[i].l;--j){
            ++bar[stk[++top]=z=a[j]];
            if(bar[z-1]&&bar[z+1])
                le[re[le[z-1]]=re[z]=re[z+1]]=le[z]=le[z-1];
            else if(bar[z-1])re[le[z]=le[z-1]]=re[z]=z;
            else if(bar[z+1])le[re[z]=re[z+1]]=le[z]=z;
            else le[z]=re[z]=z;
            tans=max(tans,re[z]-le[z]+1);
            //printf("%d %d\n",tans,z);
        }
        while(top){
            z=stk[top--];
            if(le[z]^z)re[le[z]]=z-1;
            if(re[z]^z)le[re[z]]=z+1;
            le[z]=re[z]=0,--bar[z];
        }
        as[q[i].id]=tans;
    }
    for(register int i=1;i<=m;++i)printf("%d\n",as[i]);
    return 0;
}
View Code
posted @ 2019-10-12 09:20  remarkable  阅读(151)  评论(0编辑  收藏  举报