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\n",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\n",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\n",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\n",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

 

posted @ 2019-08-22 12:09  starsing  阅读(120)  评论(0编辑  收藏  举报