zoukankan      html  css  js  c++  java
  • 【2019.10.8】备战CSP2019模拟赛

    总结

    分少因为正解打得少。

    分不够多因为暴力打得不够多。

    (到位)

    T1.方阵

    题意:

    n*m的方阵,第i列j行的值为Xij,给定几个矩形的左上角和右下角,问SUM/ MAX/ MIN(询问的矩形较长边不会大于两倍较短边)?

    题解:

    我是打的前缀和求SUM,但是遇到MAX和MIN就直接跪了,没想到打RMQ,打的枚举,拿了40暴力分。

    正解矩阵求和用前缀和,矩阵最值二维RMQ维护,特殊处理下矩阵询问,转变为询问两个正方形,保证空间合法。

    f[i][j][k]表示左上角顶点坐标为(i, j),边长为2的k次方的正方形。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=801;
    string s;
    int a[N][N],sum[N][N],f[N][N][10],g[N][N][10],p[11];
    inline int read()
    {
        int X=0,w=1; char ch=0;
        while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
        return X*w;
    }
    inline int write(int x)
    {
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    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 main(){
        freopen("phalanx.in","r",stdin);
        freopen("phalanx.out","w",stdout);
        int n=read(),m=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                f[i][j][0]=g[i][j][0]=a[i][j]=read();
                sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
            }
        for(int i=p[0]=1;i<=10;i++) p[i]=p[i-1]<<1;
        for(int k=1;k<10;k++)
            for(int i=1;i<=n && i+p[k]-1<=n;i++)
                for(int j=1;j<=m && j+p[k]-1<=m;j++)
                {
                    f[i][j][k]=max(f[i][j][k-1],f[i][j+p[k-1]][k-1]);
                    f[i][j][k]=max(f[i][j][k],max(f[i+p[k-1]][j][k-1],f[i+p[k-1]][j+p[k-1]][k-1]));
                    g[i][j][k]=min(g[i][j][k-1],g[i][j+p[k-1]][k-1]);
                    g[i][j][k]=min(g[i][j][k],min(g[i+p[k-1]][j][k-1],g[i+p[k-1]][j+p[k-1]][k-1]));
                }
        int q=read();
        while(q--)
        {
            cin>>s;
            int x1=read()+1,y1=read()+1,x2=read()+1,y2=read()+1;
            if(s=="SUM")
            {
                write(sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]),putchar('
    ');
                continue;
            }
            int ans=s=="MIN"?3000:0,z=min(log2(x2-x1+1),log2(y2-y1+1));
            if(s=="MAX")
            {
                for(int yy=y1;yy+p[z]<=y2;yy+=p[z]) ans=max(ans,max(f[x1][yy][z],f[x2-p[z]+1][yy][z]));
                for(int xx=x1;xx+p[z]<=x2;xx+=p[z]) ans=max(ans,max(f[xx][y1][z],f[xx][y2-p[z]+1][z]));
                ans=max(ans,max(f[x1][y1][z],f[x1][y2-p[z]+1][z]));
                ans=max(ans,max(f[x2-p[z]+1][y1][z],f[x2-p[z]+1][y2-p[z]+1][z]));
            }else
            {
                for(int yy=y1;yy+p[z]<=y2;yy+=p[z]) ans=min(ans,min(g[x1][yy][z],g[x2-p[z]+1][yy][z]));
                for(int xx=x1;xx+p[z]<=x2;xx+=p[z]) ans=min(ans,min(g[xx][y1][z],g[xx][y2-p[z]+1][z]));
                ans=min(ans,min(g[x1][y1][z],g[x1][y2-p[z]+1][z]));
                ans=min(ans,min(g[x2-p[z]+1][y1][z],g[x2-p[z]+1][y2-p[z]+1][z]));
            }
            write(ans),putchar('
    ');
        }
        return 0;
    }
    View Code

     

    T2.合照

    题意:

    给出n个数,有一些特定要求,形如x,y表示x一定要在y的左边,求排列方案数。

    题解:

    第一眼想序列做法,失败。第二眼考虑状压DP,时间复杂度不够优秀,可能还要加优化(可是我想不到优化方法)。看完T3再回头,可以连边...树形DP??然而敲到最后都没时间打T3的白送20分了还是敲错了只拿到40分。部分分的做法不一定是正解的暴力。(实在想不到优化八成就不是)。

    “首先有一个条件就是每一个人最多提出一个要求。
    那么连边后的dag是一个森林,不相交的n棵树。
    g[x]*=g[v]*C(size[x],size[v]);
    表示以x为根的方案数,这个用乘法原理很好理解,每一颗子树是独立的。
    然后答案也是一样的,相当于有一个超级根把所有树连在一起,所以就有:
    ans*=g[i]*C(sz,size[i]);,同理,也是独立的,直接乘就好。 ”

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define fo(i,a,b) for(int i=a;i<=b;i++)
    #define fd(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int N=2e5+5;
    int head[N],next[N],go[N],size[N],d[N];
    int tot,fac[N],inv[N],n,m,mo,f[N],g[N];
    inline void add(int x,int y)
    {
        go[++tot]=y;
        next[tot]=head[x];
        head[x]=tot;
    }
    inline int find(int x)
    {
        if (f[x]==x) return x;
        else return f[x]=find(f[x]);
    }
    inline int C(int n,int m)
    {
        return 1ll*fac[n]*inv[m]%mo*inv[n-m]%mo;
    }
    inline void dfs(int x)
    {
        g[x]=1;size[x]=0;
        for (int i=head[x];i;i=next[i])
        {
            int v=go[i];
            dfs(v);
            size[x]+=size[v];
            g[x]=1ll*g[x]*g[v]%mo*C(size[x],size[v])%mo;
        }
        size[x]++;
    }
    int main()
    {
        freopen("photo.in","r",stdin);
        freopen("photo.out","w",stdout);
        int cas;
        scanf("%d",&cas);
        while(cas--)
        {
            scanf("%d%d%d",&n,&m,&mo);
            fac[0]=inv[0]=fac[1]=inv[1]=1;
            fo(i,2,n)
            fac[i]=1ll*fac[i-1]*i%mo,inv[i]=1ll*(mo-mo/i)*inv[mo%i]%mo;
            fo(i,2,n)
            inv[i]=1ll*inv[i]*inv[i-1]%mo;
            fo(i,1,n)f[i]=i,head[i]=d[i]=0;
            int flag=0;tot=0;
            while (m--)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                if (find(x)!=find(y))f[find(x)]=find(y);
                else flag=1;
                add(y,x);
                d[x]++;
    
            }
            if (flag)
            {
                printf("0
    ");
                continue;
            }
            int ans=1,sz=0;
            fo(i,1,n)
            if (!d[i])
            {
                dfs(i);
                sz+=size[i];
    
                ans=1ll*ans*g[i]%mo*C(sz,size[i])%mo;
            }
            printf("%d
    ",ans);
        }
    }
    View Code

    T3.

    想到一个很不优的DP思路,一看就会超时, 没打,想着打完T2回头拿个20分暴力滚,转头肝T2去了。结果有人打了还拿了80分(加了优化)...所以我还是要加快肝题速度啊,才有时间打暴力。

  • 相关阅读:
    vue自定义指令
    ZOJ Problem Set–2104 Let the Balloon Rise
    ZOJ Problem Set 3202 Secondprice Auction
    ZOJ Problem Set–1879 Jolly Jumpers
    ZOJ Problem Set–2405 Specialized FourDigit Numbers
    ZOJ Problem Set–1874 Primary Arithmetic
    ZOJ Problem Set–1970 All in All
    ZOJ Problem Set–1828 Fibonacci Numbers
    要怎么样调整状态呢
    ZOJ Problem Set–1951 Goldbach's Conjecture
  • 原文地址:https://www.cnblogs.com/jian-song/p/11634925.html
Copyright © 2011-2022 走看看