zoukankan      html  css  js  c++  java
  • 20190820考试反思

      这次考试考得不够好。T1开挂做的,然后T2不是很会(思路不通),T3更没有思考,还是没能深入思考

      T1:可以说这题开挂了,因为我知道小凯的疑惑,然后这题就A了;没有什么可吹的。在考试的时候这种结论一般不是很好找,一定要大胆猜想,看看转移是否可以减少。

      按照m的dp:$f[i]=max(f[i-4],f[i-7])+a[i]$60分到手。

      然后转成按照n的dp:$f[i]=max(f[j])+a[i]$(b[i]-b[j]能被4,7表示) 然后考虑如何实现后边的限制,可以先把从1到1e5的能被4,7表示的数表打出来,发现从18开始后边都能表示,那么18之前直接维护前缀最大值即可。复杂度$O(n)$

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N=100020;
    long long f[N],maxi[N],a[N];
    bool v[30];
    struct node{long long a,b;}mo[N];
    inline int rd()
    {
        int s=0,w=1;
        char cc=getchar();
        for(;cc<'0'||cc>'9';cc=getchar()) if(cc=='-') w=-1;
        for(;cc>='0'&&cc<='9';cc=getchar()) s=(s<<3)+(s<<1)+cc-'0';
        return s*w;
    }
    bool cmp(node a,node b)
    {
        return a.b<b.b;
    }
    int main()
    {
        //freopen("data.in","r",stdin);
        //freopen("data.out","w",stdout);
        int n=rd(),m=rd();
        if(m<=100000)
        {
            memset(f,-0x3f,sizeof(f));
            for(int i=1;i<=n;i++)
            {
                int x=rd(),y=rd();
                a[y]+=x;
            }
            long long  ans=0;
            f[0]=0;
            for(int i=1;i<=m;i++)
            {
                if(i-4<0) f[i]=-0x7fffffff;
                else if(i-7<0) f[i]=f[i-4]+a[i];
                else f[i]=max(f[i-4],f[i-7])+a[i];
                ans=max(ans,f[i]);
            }
            printf("%lld
    ",ans);
        }
        else
        {
            v[0]=1;v[4]=1;v[7]=1;v[8]=1;v[11]=1;v[12]=1;v[14]=1;v[15]=1;v[16]=1;
            for(int i=1;i<=n;i++)
                mo[i].a=rd(),mo[i].b=rd();
            sort(mo+1,mo+n+1,cmp);
            memset(f,-0x3f,sizeof(f));
            f[0]=0;
            long long ans=0;
            for(int i=1;i<=n;i++)
            {
                for(int j=i-1;j>=0;j--)
                {
                    if(mo[i].b-mo[j].b>17)
                    {
                        f[i]=max(f[i],maxi[j]+mo[i].a);
                        break;
                    }
                    if(v[mo[i].b-mo[j].b]) f[i]=max(f[i],f[j]+mo[i].a);
                }
                maxi[i]=max(maxi[i-1],f[i]);
                ans=max(ans,f[i]);
            }
            printf("%lld
    ",ans);
        }
    }
    /*
    g++ 1.cpp -o 1
    ./1
    3 13
    100 4
    10 7
    1 11
    */
    View Code

      T2:差点想到正解。给n*m矩阵要求$(n+m-1)*sum (A_{i}-Avag)^{2}$最小值。看到平方不会处理就先拆出来。

      $(n+m-1)*sum(A_{i}^{2}-2A_{i}*Avag+Avag^{2})$

      $sum((n+m-1)*A{i}^2-2A_{i}*sum A_{i}+Avag*sum A_{i})$

      $(n+m-1)*sum(A_{i}^2)-(sum A_{i})^{2}$

      然后,我就傻X的用这个柿子打搜索。。。。

      题目明确提醒,矩阵元素不大于30,以前不知道他在说啥,以后应该知道他在提示可以压进状态。

      设f[s][i][j]为到i,j的和为s的最小平方和。

      转移即可。

      

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int S=30*920,N=40;
    int f[S][N][N],a[N][N];
    inline int rd()
    {
        int s=0,w=1;
        char cc=getchar();
        for(;cc<'0'||cc>'9';cc=getchar()) if(cc=='-') w=-1;
        for(;cc>='0'&&cc<='9';cc=getchar()) s=(s<<3)+(s<<1)+cc-'0';
        return s*w;
    }
    int main()
    {
        int T=rd();
        while(T--)
        {
            int n=rd(),m=rd(),maxi=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    a[i][j]=rd(),maxi=max(maxi,a[i][j]);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    for(int s=0;s<=maxi*(n+m);s++)
                        f[s][i][j]=0x7ffffff;
            f[a[1][1]][1][1]=a[1][1]*a[1][1];
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    for(int s=0;s<=maxi*(n+m);s++)
                    {
                        f[s+a[i+1][j]][i+1][j]=min(f[s+a[i+1][j]][i+1][j],f[s][i][j]+a[i+1][j]*a[i+1][j]);
                        f[s+a[i][j+1]][i][j+1]=min(f[s+a[i][j+1]][i][j+1],f[s][i][j]+a[i][j+1]*a[i][j+1]);
                    }
                }
            long long ans=0x7ffffffffffffff;
            for(int s=0;s<=maxi*(n+m);s++)
            {
                ans=min(1ll*ans,1ll*(n+m-1)*f[s][n][m]-s*s);
            }
            printf("%lld
    ",ans);
        }
    }
    /*
    g++ 2.cpp -o 2
    ./2
    1
    2 2
    1 2
    3 4
    */
    View Code

      T3:好题,再次提醒:位运算是的运算,只和位之间有关,我们可以知道,异或不满足加法结合律,那么这个就没法树DP转移。

      那么我们可以好好想一下到底怎么处理这种东西。另外,异或的数不超过16。

      性质:由于只和位有关,我们发现,假设异或的数有k位,对于后k位相同的,异或前后变化相同,我们就可以找到后k位的数是j的路径个数,然后可以通过这个数组得到答案,这个数组满足结合律,可以树上转移,另外用最朴素的f数组存路径和。

      这两个数组既然可以树上转移,那就可以换根,最终换根算出最终答案就可以了。

      

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=500020;
    int fr[N],tt,fa[N],f[N],size[N],tmp[20],s[N][20],n,m,ans;
    struct node{int to,pr,w;}mo[N*2];
    inline int rd()
    {
        int s=0,w=1;
        char cc=getchar();
        for(;cc<'0'||cc>'9';cc=getchar()) if(cc=='-') w=-1;
        for(;cc>='0'&&cc<='9';cc=getchar()) s=(s<<3)+(s<<1)+cc-'0';
        return s*w;
    }
    void add(int x,int y,int c)
    {
        mo[++tt].to=y;mo[tt].w=c;
        mo[tt].pr=fr[x];fr[x]=tt;    
    }
    void dfs1(int x)
    {
        size[x]=1;s[x][0]++;
        for(int i=fr[x];i;i=mo[i].pr)
        {
            int to=mo[i].to;
            if(to==fa[x]) continue;
            fa[to]=x;
            dfs1(to);
            f[x]+=f[to]+size[to]*mo[i].w;
            for(int j=0;j<=15;j++)
                s[x][(j+mo[i].w)&15]+=s[to][j];
            //s[x][(mo[i].w)&15]++;
            size[x]+=size[to];
        }
        /*for(int j=0;j<=15;j++)
        {
            cout<<x<<" "<<j<<" "<<s[x][j]<<endl;
        }*/
    }
    void dfs2(int x)
    {
        for(int i=fr[x];i;i=mo[i].pr)
        {
            int to=mo[i].to;
            if(to==fa[x]) continue;
            fa[to]=x;
            f[to]=f[to]+f[x]-(f[to]+size[to]*mo[i].w)+mo[i].w*(n-size[to]);
            //cout<<to<<" "<<f[to]<<endl;
            //cout<<s[4][13]<<endl;
            for(int j=0;j<=15;j++)
            {
                //cout<<to<<" "<<j<<" "<<s[x][j]<<" "<<s[to][j]<<endl;
                tmp[(mo[i].w+(j+mo[i].w)&15)&15]=s[x][(j+mo[i].w)&15]-s[to][j];
            }
            
            for(int j=0;j<=15;j++)
            {
                s[to][j]+=tmp[j];
                ///cout<<to<<" "<<j<<" "<<s[to][j]<<endl;
            }
            dfs2(to);
        }
    }
    int main()
    {
        n=rd();m=rd();
        for(int i=1;i<n;i++)
        {
            int x=rd(),y=rd(),z=rd();
            add(x,y,z);add(y,x,z);
        }
        dfs1(1);
        dfs2(1);
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=15;j++)
            {
                f[i]-=s[i][j]*j;
                f[i]+=s[i][j]*(j^m);
            }
            printf("%d
    ",f[i]-m);
        }
    }
    /*
    g++ 3.cpp -o 3
    ./3
    5 3
    1 2 1
    1 3 2
    1 4 3
    2 5 4
    */
    View Code
  • 相关阅读:
    css单行排版
    sass安装(windows版)
    php通过post将表单数据保存到数据库实例
    C#-socket简单同步通信学习
    让VS变成彩色码
    VS项目启动后 提示ID为*******的进程当前未运行
    C#实现简单验证码
    API清理xml格式数据
    VS提示-无法启动IIS Express Web服务器-的解决方法
    C#MVC中ztree的简单使用
  • 原文地址:https://www.cnblogs.com/starsing/p/11393624.html
Copyright © 2011-2022 走看看