zoukankan      html  css  js  c++  java
  • 2019.10.20 csp-s模拟测试 lrd试题 反思总结

    赶进度赶进度,丢个代码两三句备注一下完事了。

    day1:

    前面两道题没实际写代码怕印象不深所以描述一下大意。

    T1:

    题目大意:给出两个数&、|、^的结果(可能只给出其中某一项或者某两项),求这两种数有多少种选取情况。

    关键点是讨论无限解。只给出^和只给出&的情况无法确定最高位的1在哪里所以解是无穷个。

    其它情况只要把给出的数据转化成二进制一位一位讨论就行了。

    T2:

    题目大意:一开始存在一个空集A。有四种操作,给出一个集合B使A成为与B的交集或并集,以及让A中的所有元素加一或者减一。要求输出每次操作后A中元素之和。

    开桶来维护集合里存在哪些元素,当前存在的元素标记为tim。成为并集的时候,读入B集合,将里面未标记为tim的标记一下,维护现存元素的和。成为交集的时候先让tim++,对于B集合里的每个元素,若原本标记为tim-1(先前的tim)则存在于新的A中,让它被标记为当前的tim,同样维护元素的和。关于加减操作,记录一下全局总变化值val,每次读入的B数组也先变化val再进行操作。输出答案的时候考虑siz和val共同作用的影响。

    T3:

    很容易想到对于每个空地联通块统计相同颜色的方块的贡献,然后发现很多方块要被记录多次使答案变大。能想到的解决方法是容斥,统计多少方块被一个连通块记录,被两个连通块记录…枚举连通块的所有选择状态然后枚举每个方块,或者其它怎样枚举,然后爆炸。

    每个方块最多被四个连通块统计到,所以可以记录下统计到它的连通块,然后只针对这最多四个连通块的选择情况修改记录值。写一个哈希表,传进所选连通块的编号。翻众巨神们的博客发现还可以直接哈希。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1010;
    int n,m,k,tim;
    long long ans;
    int a[N][N],c[N][N],b[N][N][4];
    int h[5]={0,0,-1,0,1};
    int l[5]={0,-1,0,1,0};
    int p=1000003,mod=15000017;
    struct node{
        int x0,x1,x2,x3,col;
    }t[1000010];
    int check(int x,node xx){
        if(t[x].x0!=xx.x0)return 0;
        if(t[x].x1!=xx.x1)return 0;
        if(t[x].x2!=xx.x2)return 0;
        if(t[x].x3!=xx.x3)return 0;
        if(t[x].col!=xx.col)return 0;
        return 1;
    }
    void dfs(int x,int y){
        c[x][y]=tim;
        for(int i=1;i<=4;i++){
            int x1=x+h[i],y1=y+l[i];
            if(x1<=0||x1>n||y1<=0||y1>m)continue; 
            if(c[x1][y1]!=tim&&a[x1][y1]){
                c[x1][y1]=tim;
                if(!b[x1][y1][0])b[x1][y1][0]=tim;
                else if(!b[x1][y1][1])b[x1][y1][1]=tim;
                else if(!b[x1][y1][2])b[x1][y1][2]=tim;
                else b[x1][y1][3]=tim;
            }
            else if(!c[x1][y1]&&!a[x1][y1])dfs(x1,y1);
        }
    }
    int head[16000010*4],Next[16000010*4],v[16000010*4],cnt,siz[16000010*4],color[16000010*4];
    int has(int x0,int x1,int x2,int x3,int col){
        long long val=((((1ll*x0*p%mod+x1)%mod*p+x2)%mod*p+x3)%mod*p+col)%mod;
        for(int i=head[val];i;i=Next[i]){
            if(check(i,(node){x0,x1,x2,x3,col})){
                siz[i]++;
                return siz[i]-1;
            }
        }
        t[++cnt]=(node){x0,x1,x2,x3,col},Next[cnt]=head[val],head[val]=cnt;
        siz[cnt]=1;
        return siz[cnt]-1;
    }
    int main()
    {
    //    freopen("1.in","r",stdin);
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&a[i][j]);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(!a[i][j]&&!c[i][j]){
                    tim++;
                    dfs(i,j);
                }
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]){
                    if(b[i][j][0]){
                        ans+=has(b[i][j][0],0,0,0,a[i][j]);
                    }
                    if(b[i][j][1]){
                        ans+=has(b[i][j][1],0,0,0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][1],0,0,a[i][j]);
                    }
                    if(b[i][j][2]){
                        ans+=has(b[i][j][2],0,0,0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][2],0,0,a[i][j]);
                        ans-=has(b[i][j][1],b[i][j][2],0,0,a[i][j]);
                        ans+=has(b[i][j][0],b[i][j][1],b[i][j][2],0,a[i][j]);
                    }
                    if(b[i][j][3]){
                        ans+=has(b[i][j][3],0,0,0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][3],0,0,a[i][j]);
                        ans-=has(b[i][j][1],b[i][j][3],0,0,a[i][j]);
                        ans-=has(b[i][j][2],b[i][j][3],0,0,a[i][j]);
                        ans+=has(b[i][j][0],b[i][j][1],b[i][j][3],0,a[i][j]);
                        ans+=has(b[i][j][0],b[i][j][2],b[i][j][3],0,a[i][j]);
                        ans+=has(b[i][j][1],b[i][j][2],b[i][j][3],0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][1],b[i][j][2],b[i][j][3],a[i][j]);
                    }
                }
            }
        }
        int num=1;
        for(int i=1;i<=n;i++){
            for(int j=2;j<=m;j++){
                if(a[i][j]==a[i][j-1]&&a[i][j]){
                    num=1;
                    for(int k=0;k<=3;k++){
                        for(int l=0;l<=3;l++){
                            if(b[i][j][k]==b[i][j-1][l]&&b[i][j][k]){
                                num=0;
                                break;
                            }
                        }
                    }
                    ans+=num;
                }
            }
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]==a[i-1][j]&&a[i][j]){
                    num=1;
                    for(int k=0;k<=3;k++){
                        for(int l=0;l<=3;l++){
                            if(b[i][j][k]==b[i-1][j][l]&&b[i][j][k]){
                                num=0;
                                break;
                            }
                        }
                    }
                    ans+=num;
                }
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    哈希表
    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1010;
    int n,m,k,tim;
    long long ans;
    int a[N][N],c[N][N],b[N][N][4];
    int h[5]={0,0,-1,0,1};
    int l[5]={0,-1,0,1,0};
    int p=13131,mod=15000017;
    void dfs(int x,int y){
        c[x][y]=tim;
        for(int i=1;i<=4;i++){
            int x1=x+h[i],y1=y+l[i];
            if(x1<=0||x1>n||y1<=0||y1>m)continue; 
            if(c[x1][y1]!=tim&&a[x1][y1]){
                c[x1][y1]=tim;
                if(!b[x1][y1][0])b[x1][y1][0]=tim;
                else if(!b[x1][y1][1])b[x1][y1][1]=tim;
                else if(!b[x1][y1][2])b[x1][y1][2]=tim;
                else b[x1][y1][3]=tim;
            }
            else if(!c[x1][y1]&&!a[x1][y1])dfs(x1,y1);
        }
    }
    int head[16000010*4],Next[16000010*4],v[16000010*4],cnt,siz[16000010*4];
    int has(int x0,int x1,int x2,int x3,int col){
        long long val=((((1ll*x0*p%mod+x1)%mod*p+x2)%mod*p+x3)%mod*p+col)%mod;
        for(int i=head[val];i;i=Next[i]){
            if(v[i]==col){
                siz[i]++;
                return siz[i]-1;
            }
        }
        v[++cnt]=col,Next[cnt]=head[val],head[val]=cnt;
        siz[cnt]=1;
        return siz[cnt]-1;
    }
    int main()
    {
    //    freopen("1.in","r",stdin);
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&a[i][j]);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(!a[i][j]&&!c[i][j]){
                    tim++;
                    dfs(i,j);
                }
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]){
                    if(b[i][j][0]){
                        ans+=has(b[i][j][0],0,0,0,a[i][j]);
                    }
                    if(b[i][j][1]){
                        ans+=has(b[i][j][1],0,0,0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][1],0,0,a[i][j]);
                    }
                    if(b[i][j][2]){
                        ans+=has(b[i][j][2],0,0,0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][2],0,0,a[i][j]);
                        ans-=has(b[i][j][1],b[i][j][2],0,0,a[i][j]);
                        ans+=has(b[i][j][0],b[i][j][1],b[i][j][2],0,a[i][j]);
                    }
                    if(b[i][j][3]){
                        ans+=has(b[i][j][3],0,0,0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][3],0,0,a[i][j]);
                        ans-=has(b[i][j][1],b[i][j][3],0,0,a[i][j]);
                        ans-=has(b[i][j][2],b[i][j][3],0,0,a[i][j]);
                        ans+=has(b[i][j][0],b[i][j][1],b[i][j][3],0,a[i][j]);
                        ans+=has(b[i][j][0],b[i][j][2],b[i][j][3],0,a[i][j]);
                        ans+=has(b[i][j][1],b[i][j][2],b[i][j][3],0,a[i][j]);
                        ans-=has(b[i][j][0],b[i][j][1],b[i][j][2],b[i][j][3],a[i][j]);
                    }
                }
            }
        }
        int num=1;
        for(int i=1;i<=n;i++){
            for(int j=2;j<=m;j++){
                if(a[i][j]==a[i][j-1]&&a[i][j]){
                    num=1;
                    for(int k=0;k<=3;k++){
                        for(int l=0;l<=3;l++){
                            if(b[i][j][k]==b[i][j-1][l]&&b[i][j][k]){
                                num=0;
                                break;
                            }
                        }
                    }
                    ans+=num;
                }
            }
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]==a[i-1][j]&&a[i][j]){
                    num=1;
                    for(int k=0;k<=3;k++){
                        for(int l=0;l<=3;l++){
                            if(b[i][j][k]==b[i-1][j][l]&&b[i][j][k]){
                                num=0;
                                break;
                            }
                        }
                    }
                    ans+=num;
                }
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    直接哈希

    害,我居然不会写哈希表。丑陋取模以及丑陋模数又让这份代码交了一页,大佬们都差点没把它救回来。

    day2:

    T1:

    仔细读一遍题,发现要求给出的m长度串的最小循环节。一个字符串的所有循环节一定都是最小循环节的整数倍,利用gcd可证。

    利用kmp算法的next数组可以直接求出最小循环节,若len%(len-next[n])==0,则(len-next[n])就是最小循环节的长度。

    然后分类讨论一下,直接求出答案。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int t,n,m,nxt[1000010];
    char s[1000010];
    int main()
    {
    //    freopen("1.in","r",stdin);
    //    freopen("1.out","w",stdout);
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            scanf("%s",s+1);
            for(int i=2,j=0;i<=m;i++){
                j=nxt[i-1];
                while(s[j+1]!=s[i]&&j){
                    j=nxt[j];
                }
                if(s[j+1]==s[i])nxt[i]=j+1;
            }
            if(m%(m-nxt[m])==0&&nxt[m])printf("%lld
    ",max(1ll*m*(n-1)+nxt[m],1ll*nxt[m]));
            else printf("%lld
    ",max(1ll*m*(n-1),1ll*nxt[m]));
            for(int i=1;i<=m;i++)nxt[i]=0;
        }
        return 0;
     } 
    View Code

    改成不仔细地读一遍题。关于我连-1都没判这个问题,我笑死了。

    T2:

    不会,刚听完讲,咕着。

    T3:

    首先对于自环的情况,输出原树直径/2+1。

    其它情况则是求一个环上挂着的最长链。可能的答案存在四种:环最底下两个节点的儿子能走到的最长链,环最顶端节点(lca)除了环占用的两条链以外的儿子能走到的最长链,lca先往父亲走一步然后不返回这棵子树在整棵树上能走到的最长链,以及底端两个节点到lca路径上的节点除去被占用的这条路其它的最长链。

    dfs的时候预处理一个节点的子节点们能走到的最长链、次长链、第三长链,解决第一种情况和第二种情况。

    第三种情况,预处理每个点作为lca时的答案。这个答案可能是父亲的答案+1,也有可能是从父节点的其它子节点贡献来。讨论当前点是不是父节点记下的最长链子节点。

    第四种情况,预处理每个点的父亲如果不走它能走到的最长链,和lca一样存在倍增数组里。查询的时候注意区间范围,不能查到lca。

    害忘说了忘说了,有可能询问的两个点其中一个是另一个的祖先,这个时候特殊处理一下,大致和通常情况没什么区别。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=200010;
    int n,m;
    int ver[N*2],head[N],Next[N*2],tot,sum,x1,y1,ans;
    void add(int x,int y){
        ver[++tot]=y;
        Next[tot]=head[x];
        head[x]=tot;
    }
    int lon[N][3],k[N][3],tim[N],dep[N],lip[N];
    void dfs1(int x,int fa){
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            dep[y]=dep[x]+1;
            dfs1(y,x);
            if(tim[y]>lon[x][0]){
                lon[x][2]=lon[x][1];
                k[x][2]=k[x][1];
                lon[x][1]=lon[x][0];
                k[x][1]=k[x][0];
                lon[x][0]=tim[y];
                k[x][0]=y;
            }
            else if(tim[y]>lon[x][1]){
                lon[x][2]=lon[x][1];
                k[x][2]=k[x][1];
                lon[x][1]=tim[y];
                k[x][1]=y;
            }
            else if(tim[y]>lon[x][2]){
                lon[x][2]=tim[y];
                k[x][2]=y;
            }
        }
        tim[x]=lon[x][0]+1;
        ans=max(ans,(lon[x][0]+lon[x][1])/2+1);
    }
    int st[N][21],maxx[N][21];
    void dfs2(int x,int fa){
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            if(y==k[x][0])lip[y]=lon[x][1]+1;
            else lip[y]=lon[x][0]+1;
            lip[y]=max(lip[y],lip[x]+1);
            st[y][0]=x;
            for(int i=1;i<=20;i++){
                st[y][i]=st[st[y][i-1]][i-1];
            }
            if(k[x][0]==y)maxx[y][0]=lon[x][1];
            else maxx[y][0]=lon[x][0];
            for(int i=1;i<=20;i++)maxx[y][i]=max(maxx[st[y][i-1]][i-1],maxx[y][i-1]);
            dfs2(y,x);
        }
    }
    int get(int x,int y){
        for(int i=20;i>=0;i--){
            if(dep[st[x][i]]>dep[y])x=st[x][i];
        }
        if(st[x][0]==y){
            x1=x;
            return st[x][0];
        }
        if(dep[st[x][0]]==dep[y])x=st[x][0];
        for(int i=20;i>=0;i--){
            if(st[x][i]&&st[x][i]!=st[y][i])x=st[x][i],y=st[y][i];
        }
        x1=x,y1=y;
        return st[x][0];
    }
    void work(int x,int lca){
        for(int i=20;i>=0;i--){
            if(dep[st[x][i]]>dep[lca])sum=max(sum,maxx[x][i]),x=st[x][i];
        }
    }
    int main()
    {
    //    freopen("1.in","r",stdin);
    //    freopen("1.out","w",stdout);
        scanf("%d",&n);
        for(int i=1,x,y;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
        }
        dfs1(1,0);
        dfs2(1,0);
        scanf("%d",&m);
        for(int i=1,x,y;i<=m;i++){
            scanf("%d%d",&x,&y);
            if(x==y){
                printf("%d
    ",ans);
                continue;
            }
            x1=y1=sum=0;
            if(dep[x]<dep[y])swap(x,y);
            int lca=get(x,y);
            if(lca==y){
                work(x,lca);
                sum=max(sum,lon[x][0]);
                if(k[lca][0]==x1){
                    sum=max(sum,lon[lca][1]);
                }
                else sum=max(sum,lon[lca][0]);
                sum=max(sum,lip[lca]);
            }
            else{
                work(x,lca),work(y,lca);
                sum=max(sum,max(lon[x][0],lon[y][0]));
                if((k[lca][0]==x1||k[lca][0]==y1)&&(k[lca][1]==x1||k[lca][1]==y1)){
                    sum=max(sum,lon[lca][2]);
                }
                else if(k[lca][0]==x1||k[lca][0]==y1){
                    sum=max(sum,lon[lca][1]);
                }
                else sum=max(sum,lon[lca][0]);
                sum=max(sum,lip[lca]);
            }
            printf("%d
    ",sum);
        }
        return 0;
    }
    View Code

    在这道题上死了一下午,一个是把询问点相邻的情况和自环的情况当成同类了,一个是直接输出直径相关的答案的时候没有考虑明白答案的定义。

    感觉是和noip难度最接近的一套题…对不起,csp-s。不过大概率真正的考试题比这样的题要难吧。

    没什么发挥余地,不爆炸就万幸了(笑)

    csp-s2019爆零滚粗?

  • 相关阅读:
    testNG参数传递方式
    TestNG超详细教程
    testNG中@Factory详解
    【转】HashMap的工作原理
    shell脚本学习笔记
    awk文本处理知识汇总
    sed文本处理知识点整理
    oracle数据库sql的基本使用
    【转】Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例
    HTML5 indexedDB数据库的入门学习(二)
  • 原文地址:https://www.cnblogs.com/chloris/p/11710085.html
Copyright © 2011-2022 走看看