• 模拟测试20190811


    这次。。。。。。好像稍有起色?

    不像前几次那么差了,但是还是不尽如人意

    凭君莫话封侯事,一将功成万骨枯,也许是在暗示着什么吧

    继续保持

    简要说一下考试经历

    上来肛T1,想岔了把前缀和相减想成了相加,复杂度平添一个log,得到了和暴力一样的好成绩

    然后肛T2,很快发现是一个贪心,然而由于倍增打错以及剪枝剪错WA成了65分,鼓掌

    然后发现只剩30分钟,想T3毫无起色,开始打特判,得到了16分的好成绩

    总分60+65+16=141pts,rank10,emmm......还好吧

    T1:入阵曲

    60pts算法:n^4直接做,或者n^3logn的分治(,zkt的n^3??),没什么差别......没有

    100pts算法:我们将思路从相加改为相减,那么如果我们固定了左右边,直接开一个桶从上扫到下就好了,复杂度O(n^3)

    #include<bits/stdc++.h>
    #define ll long long
    #define re register
    #define cri const register int
    #define crs const register short
    #define re register
    #define db double
    using namespace std;
    int n,m,k,has[510];
    short tong[2000010];
    int sum[510][510];
    inline int mo(cri x){
        if(x==k) return 0;
        return x;
    }
    ll solve(crs l,crs r){
        re ll ans=0,x;
        if(l==r){
            for(int i=1;i<=m;i++)
                for(int j=i;j<=m;j++)
                    if(!((sum[l][j]-sum[l-1][j]-sum[l][i-1]+sum[l-1][i-1]+k*2)%k)) ans++;
            return ans;
        }
        short mid=l+r>>1;
        ans=solve(l,mid)+solve(mid+1,r);
        for(re short i=1;i<=m;i++)
            for(re short j=i;j<=m;j++){
                for(re short t=mid;t>=l;t--){
                    x=(sum[mid][j]-sum[mid][i-1]-sum[t-1][j]+sum[t-1][i-1]+k*2)%k;
                    tong[x]++;
                    has[t]=x;
                }
                for(re short t=mid+1;t<=r;t++){
                    x=(sum[t][j]-sum[t][i-1]-sum[mid][j]+sum[mid][i-1]+k*2)%k;
                    ans+=tong[mo(k-x)];
                }
                for(re short t=mid;t>=l;t--){
                    tong[has[t]]--;
                }
            }
        //cout<<ans<<endl;
        return ans;
    }
    signed main(){
        scanf("%d%d%d",&n,&m,&k);
        int x;ll ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) scanf("%d",&x),sum[i][j]=(sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+x+k)%k;
        for(int i=1;i<=m;i++){
            for(int j=i;j<=m;j++){
                tong[0]=1;
                for(int t=1;t<=n;t++){
                    x=(sum[t][j]-sum[t][i-1]+k)%k;
                    ans+=tong[x];tong[x]++;
                }
                for(int t=1;t<=n;t++){
                    x=(sum[t][j]-sum[t][i-1]+k)%k;
                    tong[x]--;
                }
            }
        }
        printf("%lld",ans);
    }
    View Code

    T2:将军令

    考试想了想dp感觉不可做(%%yxm),然后发现这就是个贪心

    每次找到剩余深度最深的点,找到他的k层父亲然后暴力更新这个点周围k层就好了

    复杂度O(kn)

    #include<bits/stdc++.h>
    #define ll long long
    #define re register
    #define cri const register int
    #define re register
    #define db double
    #define mp make_pair
    using namespace std;
    int f[100010][8],dep[100010],v[100010];
    int fa[100010],to[200010],la[200010],cnt,now,q[100010];
    inline void add(cri x,cri y){
        to[++cnt]=y;
        la[cnt]=fa[x];
        fa[x]=cnt;
    }
    void dfs(cri x,cri ff){
        for(int i=1;(1<<i)<=dep[x]&&i<=7;i++)
            f[x][i]=f[f[x][i-1]][i-1];
        for(int i=fa[x];i;i=la[i])
            if(to[i]!=ff){
                dep[to[i]]=dep[x]+1;
                f[to[i]][0]=x;
                dfs(to[i],x);
            }
    }
    void dfss(cri x,cri k,cri ff,cri is){
        if(is)v[x]=1;
        else v[x]=2;
        if(!k) return;
        for(int i=fa[x];i;i=la[i])
            if(to[i]!=ff&&v[to[i]]!=1){
                if(x==now&&dep[to[i]]<dep[x]||!is)dfss(to[i],k-1,x,0);
                else dfss(to[i],k-1,x,1);
            }
    }
    inline bool as(cri x,cri y){
        return dep[x]>dep[y];
    }
    signed main(){
        int n,k,t,x,y,ans=0;
        scanf("%d%d%d",&n,&k,&t);
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
            q[i]=i;
        }
        q[n]=n;
        dep[1]=1;
        dfs(1,0);
        sort(q+1,q+n+1,as);
        for(int j=1;j<=n;j++)
            if(!v[q[j]]){
                x=q[j];
                t=k;ans++;
                for(int i=5;i>=0;i--)
                    if((1<<i)<=t)x=f[x][i],t-=(1<<i);
                if(!x) break;
                now=x;
                dfss(x,k,0,1);
            }
        printf("%d",ans);
    }
    View Code

    T3:星空

    最近T3日常神仙啊......

    24分我们可以直接状压,但是我们发现根本没用到k很小这个条件

    这启发我们把用n状压改变成用k状压,需要经历下面几次题意转换

    F,我们直接最暴力地暴力翻转一段区间是O(n)的,考虑优化,区间修改转单点修改,emmm,差分啊

      我们设g[i]=a[i]^a[i+1],那么每次修改[l,r]这个区间就变成了让g[l-1],g[r]取反

      显然我们每次都要对1(表示数不同)进行操作,考虑以下两种情况

      1,改变一个1和一个0,可以看成一个1转移了位置

      2,改变两个1,可以看成一个移动到另一个的位置然后都变成0

      这样我们就把原来的操作转换成了移动

    S,原题转换成了:让原序列上的1进行移动,遇到1可以一起消除,问最小移动距离和

      等等,最小距离?边权为1?bfs不就好了嘛,bfs预处理出每两个1之间的最短路就好了,复杂度O(nmk)

      然后我们继续转换题意

    T,有2k个物品,每次选两个消去,消去操作有花费,问最小花费

      k很小,简单的状压dp就好了,复杂度O(k*22k)

      等等,枚举两个点不是k^2的吗?为什么复杂度是O(k*22k)?

      显然,我们发现每个点最终都要删去,那么我们在枚举点对的时候直接选一个点固定下来,枚举另一个点就好了

    总复杂度O(nmk+k*22k)

    #include<bits/stdc++.h>
    #define ll long long
    #define re register
    #define cri const register int
    #define re register
    #define db double
    using namespace std;
    int n,k,m,b[100];
    bool a[40010],g[40010];
    int dis[20][40010],v[40010],is[20],len[20][20],f[700010],h[70010];
    inline void spfa(cri x,cri num){
        queue<int>q;
        v[x]=num;
        q.push(x);dis[num][x]=0;
        while(!q.empty()){
            cri u=q.front();q.pop();
            for(int i=1;i<=m;i++){
                if(u+b[i]<=n&&v[u+b[i]]!=num){
                    dis[num][u+b[i]]=dis[num][u]+1;
                    v[u+b[i]]=num;
                    if(!g[u+b[i]])q.push(u+b[i]);
                }
                if(u-b[i]>=0&&v[u-b[i]]!=num){
                    dis[num][u-b[i]]=dis[num][u]+1;
                    v[u-b[i]]=num;
                    if(!g[u-b[i]]) q.push(u-b[i]);
                }
            }
        }
    }
    signed main(){
        int x,num=0;
        memset(dis,0x3f,sizeof dis);
        scanf("%d%d%d",&n,&k,&m);
        memset(a,1,sizeof a);
        for(int i=1;i<=k;i++) scanf("%d",&x),a[x]=0;
        for(int i=1;i<=m;i++) scanf("%d",&b[i]);
        for(int i=0;i<=n;i++)
            g[i]=a[i]^a[i+1];
        for(int i=0;i<=n;i++)
            if(g[i]) is[++num]=i,spfa(i,num);
        for(int i=1;i<=num;i++){
            h[1<<(i-1)]=i;
            for(int j=1;j<=num;j++)
                len[i][j]=dis[i][is[j]];
        }
        memset(f,0x3f,sizeof f);
        f[(1<<num)-1]=0;
        for(int i=(1<<num)-1;i>=1;i--){
            x=h[i&-i];
            for(int j=1;j<=num;j++)
                if(((i>>(j-1))&1)&&j!=x)
                    f[i^(1<<(j-1))^(1<<(x-1))]=min(f[i^(1<<(j-1))^(1<<(x-1))],f[i]+len[x][j]);
        }
        printf("%d",f[0]);
        return 0;
    }
    View Code

     

  • 相关阅读:
    不容易系列之(3)—— LELE的RPG难题(递推)
    亲和数(因子和)
    爬虫正式学习day2
    爬虫小练习:堆糖图片抓取--爬虫正式学习day1
    js笔记--高阶函数array的各种函数
    js笔记--高阶函数sort()
    js笔记--高阶函数filter()
    js笔记--高阶函数map() reduce()
    js笔记--方法
    js笔记--变量部分
  • 原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/11335654.html
Copyright © 2020-2023  润新知