zoukankan      html  css  js  c++  java
  • QZS8.21

    T1

    暴力(AC)

    O(n^2*k) 50

    稍微优化了一些 ,就是搞个二维前缀和(白色为1,黑色为0),O(N^2) 枚举左上角,然后每一行 每一列的处理,先减去原来那块的值,再加上k,统计是否为n, 总体复杂度O(n^2*k)

    啊满分what???(kao考试数组开小了,100变50啊啊啊)话说数据好水

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=2005; 
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n,k,ans,res=0;
    int s[N][N];
    char c[N];
    int main() {
        n=read();k=read();
        for(int i=1;i<=n;i++) {
            scanf("%s",c+1);
            for(int j=1;j<=n;j++)
                s[i][j]=(c[j]=='W');
        }
        for(int i=1;i<=n;i++) 
            for(int j=1;j<=n;j++)
                s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
        
        for(int i=1;i<=n;i++) 
            if(s[i][n]==n) ans++;
        for(int i=1;i<=n;i++) 
            if(s[n][i]==n) ans++;
        int pre,sum,mx;
        for(int i=1;i<=n-k+1;i++)
            for(int j=1;j<=n-k+1;j++) {
                mx=ans;
                for(int p=i;p<i+k;p++) {//横着
                    pre=s[p][j+k-1]+s[p-1][j-1]-s[p-1][j+k-1]-s[p][j-1];
                    sum=s[p][n]-s[p-1][n]-pre+k;
                    if(sum==n&&s[p][n]-s[p-1][n]!=n) mx++;
                }
                for(int p=j;p<j+k;p++) {
                    pre=s[i+k-1][p]+s[i-1][p-1]-s[i-1][p]-s[i+k-1][p-1];
                    sum=s[n][p]-s[n][p-1]-pre+k;
                    if(sum==n&&s[n][p]-s[n][p-1]!=n) mx++;
                }
                res=max(mx,res);
            }
         printf("%d
    ",res);
    }
    /*
    4 2
    BWWW
    WBBW
    WBBW
    WWWB 
    */
     
    

    正解

    差分思想

    考虑每个点成为最后求的k*k矩阵的左端点所能对ans的贡献

    我们要找的是贡献最大的点,

    正着想是枚举左端点然后去算对ans的贡献

    那么我们其实可以反着想——

    如果某一行/列能够被k个点覆盖后完全为白色,那么我们可以找出 能把这行/列覆盖为白色的左端点的位置矩阵,对于这个矩阵每个值(设为s)+1,然后这里矩阵加一就用到了差分的思想,

    具体的见下图

    image-20200821150653628

    inline void add(int x,int y,int xx,int yy) {
        ++s[x][y];
        --s[x][yy+1];
        --s[xx+1][y];
        ++s[xx+1][yy+1];
    }
    

    O(n^2)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=2005; 
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n,k,ans=0,res=0;
    int s[N][N];
    char mp[N][N];
    bool flag;
    inline void Max(int &x,int y) {if(x<y)x=y;}
    inline void Min(int &x,int y) {if(x>y)x=y;}
    inline void add(int x,int y,int xx,int yy) {
        ++s[x][y];
        --s[x][yy+1];
        --s[xx+1][y];
        ++s[xx+1][yy+1];
    }
    int main() {
        n=read();k=read();
        for(int i=1;i<=n;i++)
            scanf("%s",mp[i]+1);
        for(int i=1;i<=n;i++) {//横着
            int l=1,r=n,flag=0;
            for(int j=1;j<=n;j++) {
                if(mp[i][j]=='B') {
                    Max(l,j-k+1);
                    Min(r,j);
                    flag=1;
                }
            }
            if(!flag) {++ans;continue;}
            if(l<=r)add(max(1,i-k+1),l,i,r);
        }
        for(int j=1;j<=n;j++) {//竖着
            int l=1,r=n,flag=0;
            for(int i=1;i<=n;i++) {
                if(mp[i][j]=='B') {
                    Max(l,i-k+1);
                    Min(r,i);
                    flag=1;
                }
            }
            if(!flag) {++ans;continue;}
            if(l<=r)add(l,max(1,j-k+1),r,j);
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                Max(res,ans+s[i][j]);
        printf("%d
    ",res);
        return 0;
    }
    
    

    T2

    O(n^2) 暴力

    dp+st表!!!爆零???啊啊啊啊?算法错了???

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=5005; 
    const int mod=1<<30; 
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n,x,y,z,m;
    int b,b1,b2,p_pre,p_now,l,r;
    int mi[N][N],mx[N][N];
    struct RMQ {
        int log2[N];
        void init() {
            log2[0]=-1;
            for(int i=1;i<=n;i++) log2[i]=log2[i>>1]+1;
            for(int j=1;j<30;j++)
                for(int i=1;i+(1<<j)<=n+1;i++) {
                    mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
                    mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
                }
        }
        int query_mx(int ql,int qr) {
            int k=log2[qr-ql+1];
            return max(mx[ql][k],mx[qr-(1<<k)+1][k]);
        }
        int query_mi(int ql,int qr) {
            int k=log2[qr-ql+1];
            return min(mi[ql][k],mi[qr-(1<<k)+1][k]);
        }
    }rmq;
    int f[N];
    int main() {
        memset(mi,0x3f,sizeof(mi));
        n=read();
        x=read(),y=read(),z=read(),b1=read(),b2=read(),m=read();
        p_pre=0;
        int i=1;
        for(int j=1;j<=m&&i<=n;j++) {
            p_now=read();l=read();r=read();
            if(i>p_pre&&i<=p_now) {
                b=(long long)(x*b1+y*b2+z)%mod;
                mx[i][0]=mi[i][0]=b%(r-l+1)+l;
                b2=b1,b1=b;
                i++;
            }
            p_pre=p_now;
        } 
        rmq.init();
        for(i=1;i<=n;i++)
            for(int j=0;j<i;j++)
                f[i]=max(f[i],f[j]+rmq.query_mx(j+1,i)-rmq.query_mi(j+1,i));
        printf("%d
    ",f[n]);
        return 0;
    }
    
    /*
    5 
    1 1 1 1 1 5
    1 1 1
    2 2 2
    3 3 3
    4 1 1
    5 2 2
    */
    
    

    正解

    如果有一组解使得某一段不是单调的,那么可以把他分成两端单调的使极差之和比原来大

    例子:a<b<c<d

    (a,c,b,d) —— ans= d-a

    (a,c,b,d) —— (a,c)(b,d) ——ans’=c-a+d-b =d-a+c-b 显然c-b>0所以 ans’>ans

    我们只要O(n) DP在每个极值left/right分开即可

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int N=10000005; 
    const int inf=0x3f3f3f3f3f3f3f3f; 
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    
    int n,x,y,z,m;
    int b[N],pos,r,a[N];
    long long ans[2];
    int main() {
        n=read();
        x=read(),y=read(),z=read(),b[1]=read(),b[2]=read(),m=read();
        pos=0;
        for(int i=3;i<=n;i++)
            b[i]=(1ll*x*b[i-1]+1ll*y*b[i-2]+z)&((1<<30)-1);
        int np,l,r;
        for(int i=1;i<=m;i++) {
            np=read();l=read();r=read();
            while(pos<np) {
                ++pos;
                a[pos]=b[pos]%(r-l+1)+l;
            }
        } 
        ans[0]=-inf;ans[1]=0;
        int mx=0,mi=0x3f3f3f3f;
        for(int i=1;i<=n;i++) {
            if(i>1 && i<n && ((a[i]<a[i-1]&&a[i]<=a[i+1])||(a[i]>a[i-1]&&a[i]>=a[i+1]))) {//极值点
                long long l=-inf,r=-inf;//l,r表示在左边和右边划分的ansmax
                l=max(l,ans[0]+max(mx,a[pos])-min(mi,a[pos]));
                if(pos!=i-1) l=max(l,ans[1]+mx-mi);
                else l=max(l,ans[1]);
                r=max(r,ans[0]+max(mx,max(a[i],a[pos]))-min(mi,min(a[i],a[pos])));
                r=max(r,ans[1]+max(a[i],mx)-min(a[i],mi));
                ans[0]=l,ans[1]=r;pos=i;
                mx=0,mi=0x3f3f3f3f;
            } else 
                mx=max(mx,a[i]),mi=min(mi,a[i]);//mx,mi是这段区间的
        }
        printf("%lld
    ",max(ans[0]+max(mx,a[pos])-min(mi,a[pos]),ans[1]+mx-mi));
        return 0;
    }
    

    T3

    gugugu

  • 相关阅读:
    《算法导论》读书笔记之第16章 贪心算法—活动选择问题
    C语言综合实验1—学生信息管理系统
    《算法导论》读书笔记之第15章 动态规划[总结]
    《算法导论》读书笔记之第11章 散列表
    模板类中定义list<T>::iterator iter在g++下不识别的解决办法
    C语言参考程序—无符号一位整数的四则运算
    《算法导论》读书笔记之第15章 动态规划—最优二叉查找树
    C语言综合实验2—长整数运算
    递归与尾递归总结
    《算法导论》读书笔记之第13章 红黑树
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13659977.html
Copyright © 2011-2022 走看看