2018.6.12模拟赛

第一题是鼎纹。小块的1去匹配大块的1。

  记录一下1的位置,然后模拟即可。

  而且考试的时候没有记录大块的1的位置。记录的话可以更快。

  但是考试时写的还有什么不对?就算把 if ( ! cx )改成用vis判断也还是不对!

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1005;
int T,n,m,nn,mm,a[N][N],b[N][N],tot,cnt;
bool flag;
struct Node{
    int x,y;
}nt[N];
void init()
{
    int cx=0;
    for(int i=1;i<=nn;i++)
        for(int j=1;j<=mm;j++)
            if(b[i][j])
            {
                if(!cx)cx=i;
                nt[++tot].x=i-cx+1;nt[tot].y=j;
            }
}
int main()
{
    freopen("grain.in","r",stdin);
    freopen("grain.out","w",stdout);
    scanf("%d",&T);
    while(T--)
    {
        cnt=0;tot=0;flag=0;
        scanf("%d%d%d%d",&n,&m,&nn,&mm);
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
        {
            scanf("%1d",&a[i][j]);if(a[i][j])cnt++;
        }
        for(int i=1;i<=nn;i++)for(int j=1;j<=mm;j++)scanf("%1d",&b[i][j]);
        init();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                if(a[i][j])
                {
                    int fx=i-1,fy=j-nt[1].y;
                    for(int k=1;k<=tot;k++)
                    {
                        int x=nt[k].x+fx,y=nt[k].y+fy;
                        if(x<1||x>n||y<1||y>n||a[x][y]!=1){flag=1;break;}
                        a[x][y]=0;cnt--;
                    }
                    if(flag)break;
                }
            if(flag)break;
        }
        if(flag||cnt)printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}
考试时的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=1005;
int T,n,m,nn,mm,cnt,ynt;
char a[N][N],b[N][N];
bool flag;
struct Node{
    int x,y;
}ct[N*N],yt[N*N];
int read()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
void init()
{
    cnt=0;
    for(int i=1;i<=nn;i++)
        for(int j=1;j<=mm;j++)
            if(b[i][j]=='1')
            {
                ct[++cnt].x=i;ct[cnt].y=j;
            }
    ynt=0;
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
        if(a[i][j]=='1')yt[++ynt].x=i,yt[ynt].y=j;
}
int main()
{
    freopen("grain.in","r",stdin);
    freopen("grain.out","w",stdout);
    T=read();
    while(T--)
    {
        n=read();m=read();nn=read();mm=read();
        for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
        for(int i=1;i<=nn;i++)scanf("%s",b[i]+1);
        init();
        for(int l=1;l<=ynt;l++)
        {
            if(a[yt[l].x][yt[l].y]=='0')continue;
            int fx=yt[l].x-ct[1].x,fy=yt[l].y-ct[1].y;
            for(int k=1;k<=cnt;k++)
            {
                int x=ct[k].x+fx,y=ct[k].y+fy;
                if(x>=1&&x<=n&&y>=0&&y<=m&&a[x][y]=='1')a[x][y]='0';
                else {
                    flag=1;break;
                }
            }
            if(flag)break;
        }
        if(flag)printf("NO\n"),flag=0;
        else printf("YES\n");
    }
    return 0;
}
View Code

第二题是LICS模板+输出方案。

  一定要记住n^2的LICS模板!记录pre需要带上第一维,不知道为什么。可能省掉第一维后pre可能重复?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int N=5005;
int n,m,tot,f[N<<1],dp[N];
ll a[N],b[N],id[N<<1],tp[N<<1],pre[N<<1],v[N<<1];
int read()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
int readl()
{
    ll ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
void init()
{
    sort(tp+1,tp+n+m+1);tot=unique(tp+1,tp+n+m+1)-tp-1;//
    for(int i=1;i<=n;i++){
        ll tmp=a[i];a[i]=lower_bound(tp+1,tp+tot+1,a[i])-tp;id[a[i]]=tmp;
    }
    for(int i=1;i<=m;i++){
        ll tmp=b[i];b[i]=lower_bound(tp+1,tp+tot+1,b[i])-tp;id[b[i]]=tmp;
    }
}
void add(ll x,int k)
{
    ll tx=x;
    for(;x<=tot;x+=(x&-x)) if(k>f[x])
        f[x]=k,v[x]=tx;//v:f记录的max(长度)指向的是哪个值 
}
int query(ll k)
{
    int mx=0;ll x=k-1;
    for(;x;x-=(x&-x)) if(f[x]>mx)
        mx=f[x],pre[k]=v[x];//pre:以k结尾的上一个值 
    return mx;
}
int main()
{
    freopen("sail.in","r",stdin);
    freopen("sail.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++)a[i]=readl(),tp[i]=a[i];
    m=read();
    for(int i=1;i<=m;i++)b[i]=readl(),tp[i+n]=b[i];
    init();
    for(int i=1;i<=n;i++)
    {
        memset(f,0,sizeof f);
        for(int j=1;j<=m;j++)
        {
            add(b[j],dp[j]);
            if(a[i]==b[j])dp[j]=query(b[j])+1;
        }
        for(int j=1;j<=m;j++)add(b[j],dp[j]);
    }
    tot++;
    int ans=query(tot),cnt=0;
    while(pre[tot])tp[++cnt]=pre[tot],tot=pre[tot];
    printf("%d\n",ans);
    for(int i=cnt;i;i--)printf("%lld ",id[tp[i]]);
    
    return 0;
}
考试时的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define ll long long
using namespace std;
const int N=5005;
int n,m,ans,rd,cnt,dp[N],pre[N];
ll a[N],b[N],as[N];
ll red()
{
    ll ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
int read()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
int main()
{
    freopen("sail.in","r",stdin);
    freopen("sail.out","w",stdout);
    n=read();for(int i=1;i<=n;i++)a[i]=red();
    m=read();for(int i=1;i<=m;i++)b[i]=red();
    for(int i=1;i<=n;i++)
    {
        ll mx=0;int pos=0;
        for(int j=1;j<=m;j++)
            if(a[i]==b[j]&&mx+1>dp[j])
            {
                dp[j]=mx+1;pre[j]=pos;
                if(dp[j]>ans)ans=dp[j],rd=j;
            }
            else if(b[j]<a[i]&&dp[j]>mx)mx=dp[j],pos=j;
    }
    printf("%d\n",ans);
    while(rd)
    {
        as[++cnt]=rd;rd=pre[rd];
    }
    for(int i=cnt;i;i--)printf("%lld ",b[as[i]]);
    return 0;
}
一维的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define ll long long
using namespace std;
const int N=5005;
int n,m,ans,rd,cnt,dp[N][N],pre[N][N];
ll a[N],b[N],as[N];
ll red()
{
    ll ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
int read()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
int main()
{
    freopen("sail.in","r",stdin);
    freopen("sail.out","w",stdout);
    n=read();for(int i=1;i<=n;i++)a[i]=red();
    m=read();for(int i=1;i<=m;i++)b[i]=red();
    for(int i=1;i<=n;i++)
    {
        ll mx=0;int pos=0;
        for(int j=1;j<=m;j++)
            if(a[i]==b[j]&&mx+1>dp[i][j])
            {
                dp[i][j]=mx+1;pre[i][j]=pos;
                if(dp[i][j]>ans)ans=dp[i][j],rd=j;
            }
            else if(a[i]!=b[j])
            {
                dp[i][j]=dp[i-1][j];
                if(b[j]<a[i]&&dp[i][j]>mx)mx=dp[i][j],pos=j;
            }
    }
    printf("%d\n",ans,rd);
    for(int i=n;rd;i--)
    {
        if(a[i]==b[rd])as[++cnt]=rd,rd=pre[i][rd];
    }
    for(int i=cnt;i;i--)printf("%lld ",b[as[i]]);
    return 0;
}
View Code

第三题是莫队。

  考试时想到莫队,却不知道怎么O(1)查询。后来得知莫队的正确用法!

  mx一定是边扩展边求的。利用每一块内的 r 递增的性质,不用在意 r 。

    关键是每一块的 l 可能需要减某些值。mx是不支持减的。

      所以对于每个 l 可以从它所在的块的右端点每次暴力扩展到它!

  换 l 的时候把 l 到 r 整个暴力一遍就行。复杂度 nsqrt(n) 。

  题解给的方法慢多了。是把整块的信息记录下来,每次 l 和 r 两端暴力。

  !!这两种方法都不能随便用memset,不然会慢得不行!!!所以清空值就再跑一遍刚才的循环。这比memset快多了!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define ll long long
using namespace std;
const int N=1e5+5,K=315;
int n,m,base,tot;
ll a[N],tp[N],id[N],sum[N],mx;
ll mxx[N/K+5][N/K+5],s[N/K+5][N];
struct Ques{
    int l,r,bh,id;
}q[N];
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
ll rdl()
{
    ll ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
bool cmp(Ques a,Ques b){return a.bh==b.bh?a.r<b.r:a.bh<b.bh;}
int hb(int a){return (a-1)/base+1;}
void init()
{
    int nt=hb(n);
    for(int i=1;i<=nt;i++)
    {
        int d=min(i*base,n);
        for(int j=(i-1)*base+1;j<=d;j++)s[i][a[j]]+=id[a[j]];
    }
    for(int i=1;i<=nt;i++)for(int j=1;j<=tot;j++)s[i][j]+=s[i-1][j];
    for(int i=1;i<=nt;i++)
        for(int j=i;j<=nt;j++)
        {
            mxx[i][j]=mxx[i][j-1];
            int d=min(j*base,n);
            for(int k=(j-1)*base+1;k<=d;k++)mxx[i][j]=max(mxx[i][j],s[j][a[k]]-s[i-1][a[k]]);
        }
}
int main()
{
    freopen("mode.in","r",stdin);
    freopen("mode.out","w",stdout);
    n=rdn();m=rdn();for(int i=1;i<=n;i++)tp[i]=a[i]=rdl();
    sort(tp+1,tp+n+1);tot=unique(tp+1,tp+n+1)-tp-1;
    for(int i=1;i<=n;i++)
    {
        ll tmp=a[i];a[i]=lower_bound(tp+1,tp+tot+1,a[i])-tp;id[a[i]]=tmp;
    }
    base=sqrt(n);
    for(int i=1;i<=m;i++)
    {
        q[i].l=rdn();q[i].bh=hb(q[i].l);q[i].r=rdn();q[i].id=i;
    }
    init();
    for(int i=1,qd;i<=m;i++)
    {
        if(hb(q[i].r)-q[i].bh<=1)
        {
            mx=0;
            for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]);
            for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]-=id[a[j]];
            printf("%lld\n",mx);continue;
        }
        int x=q[i].bh,y=hb(q[i].r);
        mx=mxx[x+1][y-1];qd=q[i].bh*base;
        for(int j=q[i].l;j<=qd;j++)
            sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]+s[y-1][a[j]]-s[x][a[j]]);
        for(int j=(y-1)*base+1;j<=q[i].r;j++)
            sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]+s[y-1][a[j]]-s[x][a[j]]);
        for(int j=q[i].l;j<=qd;j++)sum[a[j]]-=id[a[j]];
        for(int j=(y-1)*base+1;j<=q[i].r;j++)sum[a[j]]-=id[a[j]];
        printf("%lld\n",mx);
    }
    return 0;
}
题解方法的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m,base,tot;
ll a[N],tp[N],id[N],sum[N],mx,tsum[N],tmx,ans[N];
struct Ques{
    int l,r,bh,id;
}q[N];
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
ll rdl()
{
    ll ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar();
    return ret;
}
bool cmp(Ques a,Ques b){return a.bh==b.bh?a.r<b.r:a.bh<b.bh;}
int hb(int a){return (a-1)/base+1;}
int main()
{
    freopen("mode.in","r",stdin);
    freopen("mode.out","w",stdout);
    n=rdn();m=rdn();for(int i=1;i<=n;i++)tp[i]=a[i]=rdl();
    sort(tp+1,tp+n+1);tot=unique(tp+1,tp+n+1)-tp-1;
    for(int i=1;i<=n;i++)
    {
        ll tmp=a[i];a[i]=lower_bound(tp+1,tp+tot+1,a[i])-tp;id[a[i]]=tmp;
    }
    base=sqrt(n);
    for(int i=1;i<=m;i++)
    {
        q[i].l=rdn();q[i].bh=hb(q[i].l);q[i].r=rdn();q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    for(int i=1,qd,dr;i<=m;)
    {
        while(hb(q[i].r)==q[i].bh&&i<=m)
        {
            mx=0;
            for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]);
            for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]-=id[a[j]];
            ans[q[i].id]=mx;i++;
        }
        if(i>m)break;
        mx=0;
        qd=q[i].bh*base+1;
        for(dr=qd;dr<=q[i].r;dr++)sum[a[dr]]+=id[a[dr]],mx=max(mx,sum[a[dr]]);
        do{
            for(;dr<=q[i].r;dr++)sum[a[dr]]+=id[a[dr]],mx=max(mx,sum[a[dr]]);
            tmx=mx;
            for(int j=q[i].l;j<qd;j++)tsum[a[j]]+=id[a[j]],tmx=max(tmx,tsum[a[j]]+sum[a[j]]);
            for(int j=q[i].l;j<qd;j++)tsum[a[j]]-=id[a[j]];
            ans[q[i].id]=tmx;i++;
        }while(q[i].bh==q[i-1].bh&&i<=m);
        for(int j=qd;j<=q[i-1].r;j++)sum[a[j]]-=id[a[j]];
    }
    for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Narh/p/9182449.html