zoukankan      html  css  js  c++  java
  • 校内模拟赛(三)(9.24)

    吐嘈:啦啦啦,hale又菜又弱,最近补CF题觉得自己快傻了

    小奇挖矿2(mining)
    【题目背景】
    小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎。
    
    【问题描述】
    现在有m+1个星球,从左到右标号为0到m,小奇最初在0号星球。
    有n处矿体,第i处矿体有ai单位原矿,在第bi个星球上。
    由于飞船使用的是老式的跳跃引擎,每次它只能从第x号星球移动到第x+4号星球或x+7号星球。每到一个星球,小奇会采走该星球上所有的原矿,求小奇能采到的最大原矿数量。
    注意,小奇不必最终到达m号星球。
    
    【输入格式】
    第一行2个整数n,m。
    接下来n行,每行2个整数ai,bi。
     
    【输出格式】
    输出一行一个整数,表示要求的结果。
    
    【样例输入】
    3 13
    100 4
    10 7
    1 11
    
    【样例输出】
    101
    
    【样例解释】
    第一次从0到4,第二次从4到11,总共采到101单位原矿。
    
    【数据范围】
    对于20%的数据 n=1,m<=10^5
    对于40%的数据 n<=15,m<=10^5
    对于60%的数据 m<=10^5
    对于100%的数据 n<=10^5,m<=10^91<=ai<=10^41<=bi<=m
    View Code

    第一题:

    显然六十分是白给的,学过DP的都会。。。

    说说正解吧,我们上去第一眼就觉得这个很像跳石子那道题,于是大家都考虑对坐标进行压缩,这明显在emmmm

    于是我们,忽然灵光乍现,是不是很像小凯的疑惑,嘿嘿,这便是我觉得最精妙的地方

    我们先处理出来4,7两个能表示出来的步数,我们发现他最小不表示出来的是17

    于是以此为契机,进行暴力转移,考虑前面的如何转移过来,维护一个最大值数组即可qwq

    时间复杂度O(n);

    #include<bits/stdc++.h>
    #define I inline
    using namespace std;
    #define LL long long
    const int N=1e5+7;
    LL mx[N],dp[N],w[N];
    int m,n;
    LL ans;
    struct node
    {
        int pos,cost;
        bool operator<(const node &x) const
        {
            return pos<x.pos;
        }
    } t[N];
    bool vis[19];
    I int read()
    {
        int x=0,f=1;char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int main()
    {
        freopen("mining.in","r",stdin);
        freopen("mining.out","w",stdout);
        n=read();m=read();
        for (int i=1;i<=n;i++) t[i].cost=read(),t[i].pos=read();
        sort(t+1,t+n+1);
        vis[0]=true;
        for (int i=1;i<=19;i++)
        if (vis[i-4]||vis[i-7]) vis[i]=true;
        for (int i=1;i<=n;i++)
        {
            int k=1;
            while (true)
            {
                int p=i-k;k++;
                if (p<0) break;
                int dis=t[i].pos-t[p].pos;
                if (dis>=18) 
                {
                    dp[i]=max(dp[i],mx[p]+t[i].cost);
                    break;
                }
                else if (vis[dis]) dp[i]=max(dp[i],dp[p]+t[i].cost);
                
            }
            mx[i]=max(mx[i-1],dp[i]);
        }
        LL ans=0;
        for (int i=1;i<=n;i++) ans=max(ans,mx[i]);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    第二题:

    刚开始的时候便只写了个暴搜,预计三十分,

    但是又看了看这个矩阵里面的元素大小,哎呀,很奇怪,只有30以下,这一定是突破口

    于是我们正解也就呼之欲出了

    dp[i][j][k]表示到达坐标为(i,j)这个点,元素总和为k的元素平方的和

    我们为了搞掉他的平均数的后效型,对原式子进行转化

    那么答案不难推出便是:min((n+m+1)*dp[i][j][k]-k*k)

    直接暴力转移即可

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,T;
    int a[50][50];
    int dp[50][50][2000];
    int ans,maxn;
    void init()
    {
        ans=1<<30;
        memset(dp,0x3f,sizeof(dp));
    }
    int sqr(int x) {return x*x;} 
    int main()
    {
        freopen("matrix.in","r",stdin); 
        freopen("matrix.out","w",stdout); 
        scanf("%d",&T);
        while(T--)
        {
            init(); 
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    scanf("%d",&a[i][j]);
            dp[1][1][a[1][1]]=sqr(a[1][1]);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    for(int k=a[i][j];k<=1800;k++)
                        dp[i][j][k]=min(dp[i][j][k],min(dp[i-1][j][k-a[i][j]],dp[i][j-1][k-a[i][j]])+sqr(a[i][j]));
            for(int i=a[n][m];i<=1800;i++)
                if(dp[n][m][i]<1061109567)
                    ans=min(ans,dp[n][m][i]*(n+m-1)-i*i);
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    第三题:

    说句实话,真心写不出来满分。。。。。。。。(hale是个傻X

    我们考虑部分分吧

    对于前三十分:直接对于每个点进行暴力计算,时间复杂度O(n^2);

    对于M=1的情况:我们变相考虑一条边对于这个树的影响,不难发现每次减少量为,当前边的左右两边节点差值

            我们钦定1为根节点,先暴力求出问题答案,之后转移即可

            时间复杂度:O(n) 

    #include<bits/stdc++.h>
    #define I inline
    using namespace std;
    const int N=2e5+7;
    int m,n,ans[N],cnt,head[N],M,size[N];
    struct edge
    {
        int nx,to,dis;
    } e[N];
    void add_edge(int a,int b,int dist)
    {
        cnt++;e[cnt].nx=head[a];e[cnt].to=b;e[cnt].dis=dist;head[a]=cnt;
    }
    I int read()
    {
        int x=0,f=1;char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    I void write(int x)
    {
        if(x<0){putchar('-');x=-x;}
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    void dfs1(int x,int fa,int dis,int p)
    {
        for (int i=head[x];i;i=e[i].nx)
        {
            int y=e[i].to;
            if (y==fa) continue;
            ans[p]+=(dis+e[i].dis)^M;
            dfs1(y,x,dis+e[i].dis,p);
        }
    }
    void solve1()
    {
        for (int i=1;i<=n;i++)
        dfs1(i,0,0,i);
        for (int i=1;i<=n;i++) write(ans[i]),puts("");
    }
    void dfs(int x,int fa)
    {
        size[x]=1;
        for (int i=head[x];i;i=e[i].nx)
        {
            int y=e[i].to;
            if (y==fa) continue;
            dfs(y,x);
            size[x]+=size[y];
        }
    }
    void dfs2(int x,int fa)
    {
        for (int i=head[x];i;i=e[i].nx)
        {
            int y=e[i].to;
            if (y==fa) continue;
            ans[y]=ans[x]+e[i].dis*size[y];
            dfs2(y,x);
        }
    }
    void solve2()
    {
        dfs1(1,0,0,1);
        dfs(1,0);
        for (int i=1;i<=n;i++) size[i]=n-2*size[i];
        dfs2(1,0);
        for (int i=1;i<=n;i++) write(ans[i]),puts("");
    }
    int main()
    {
        freopen("warehouse.in","r",stdin);
        freopen("warehouse.out","w",stdout);
        n=read(),M=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read(),z=read();
            add_edge(x,y,z);add_edge(y,x,z);
        }
        if (M!=0) solve1();
        else solve2();
        return 0;
    }
    View Code

    正解:(真心不会了,最后膜的大佬代码

    我们还是考虑,一个边对于一个树的影响,异或只影响后四位,于是我们就直接把边的边权拆了

    然后再最后总和出来就好了,(这么智障的东西都搞不出来。。。)

    #include<bits/stdc++.h>
    #define LL long long
    #define I inline
    using namespace std;
    const int N=2e5+7;
    int M,n,cnt,head[N];
    int ans[N],g[N][16],dp[N],size[N];
    I int read()
    {
        int x=0,f=1;char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void write(int x)
    {
        if(x<0){putchar('-');x=-x;}
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    struct edge
    {
        int nx,to,dis;
    } e[N];
    void add_edge(int a,int b,int dis)
    {
        cnt++;e[cnt].nx=head[a];e[cnt].to=b;e[cnt].dis=dis;head[a]=cnt;
    }
    void dfs1(int x,int fa)
    {
        for (int i=head[x];i;i=e[i].nx)
        {
            int y=e[i].to;if (y==fa) continue;
            dfs1(y,x);
            dp[x]+=dp[y]+e[i].dis/16;
            g[x][e[i].dis%16]++;
            for (int j=0;j<16;j++)
            {
                int k=j+e[i].dis;
                dp[x]+=k/16*g[y][j];
                g[x][k%16]+=g[y][j];
            }
        }
    }
    void dfs2(int x,int fa)
    {
        for (int i=head[x];i;i=e[i].nx)
        {
            int y=e[i].to;if (y==fa) continue;
            int tmp=dp[x]-dp[y];
            for (int j=0;j<16;j++)
            {
                int k=j+e[i].dis;
                tmp-=(k/16)*g[y][j];
                size[k%16]=g[x][k%16]-g[y][j];
            }
            size[e[i].dis%16]--;
            dp[y]+=tmp;
            g[y][e[i].dis%16]++;
            for (int j=0;j<16;j++)
            {
                int k=j+e[i].dis;
                dp[y]+=k/16*size[j];
                g[y][k%16]+=size[j];
            }
            dfs2(y,x);
        }
    }
    int main()
    {
        freopen("warehouse.in","r",stdin);
        freopen("warehouse.out","w",stdout);
        n=read(),M=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read(),z=read();
            add_edge(x,y,z);add_edge(y,x,z);
        }
        dfs1(1,0);
        dfs2(1,0);
        for (int i=1;i<=n;i++)
        {
            LL ans=dp[i]*16;
            for (int j=0;j<16;j++) ans+=(j^M)*g[i][j];
            write(ans);puts("");
        }
        return 0;
    }
    View Code
    慢即是快,细则是能,于小处铸迤逦
  • 相关阅读:
    【Log】【Log4j】【1】log4j日志的输出级别
    【Word&Excel】【1】更新Word的目录
    【服务器】【Windows】【5】让bat执行完后不关闭
    【Mybatis】【5】Oralce in 语句中当in(1,2,3...) 条件数量大于1000将会报错
    【JS插件】【1】移动端(微信等)使用 vConsole调试console
    【Oracle】【10】去除数据中的html标签
    【其他】【前端安全】【1】XSS攻击
    hdu 4433
    hdu 4435
    hdu 4752
  • 原文地址:https://www.cnblogs.com/Hale522520/p/11590380.html
Copyright © 2011-2022 走看看