2018.7.23模拟考试

天我居然A了一道题???怕不是把明年的运气都用光了

T1 题意简述:给出两个n*n的矩阵,m次询问它们的积中给定子矩阵的数值和。

             n<=2000,m<=50000

   解题思路:这道题其实最主要的是这个...每个测试点时限6秒

             这告诉我们...暴力就能过...

             当然也不能随便暴力。分别做前缀和即可。复杂度O(nm)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#define ll long long
using namespace std;
ll n,m;
ll ans,suma[2010][2010],sumb[2010][2010];
ll read()
{
    ll f=1;ll x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;return x;
}
int main()
{
//    system("CreatRand.exe");
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);
//    ll st=clock();
    n=read(),m=read();
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=n;j++)
            suma[i][j]=read(),suma[i][j]+=suma[i-1][j];
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=n;j++)
            sumb[i][j]=read(),sumb[i][j]+=sumb[i][j-1];
    for(ll i=1;i<=m;i++)
    {
        ans=0;
        ll xa=read(),ya=read(),xb=read(),yb=read();
        if(xa>xb) swap(xa,xb);
        if(ya>yb) swap(ya,yb);
        for(ll i=1;i<=n;i++)
            ans+=(suma[xb][i]-suma[xa-1][i])*(sumb[i][yb]-sumb[i][ya-1]);
        printf("%lld
",ans);
    }
//    ll ed=clock();
//    printf("%lld
",ed-st);
    return 0;
}

T2 题意简述平面上有N个整数坐标点。如果将点(x0,y0)移动到(x1,y1),则代价为它们之间的切比雪

             夫距离。求使得K个点在同一位置上最少需要的代价。

             N≤50,K=(1,N),0≤xi≤yi≤10^6

   解题思路:有一条很显然的性质:这个同一位置的横坐标必与某个点的横坐标相同。纵坐标亦然。

             至于怎么证明...感性理解就好。(略略略)

             因此只需要枚举出所有满足条件的点(最多n^2个),分别求出其与n个坐标点的距离,排】

             序后做前缀和,分别取最小值即可。

             能这么做的原因是因为数据太水。正解似乎是平衡树。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int n,cnt,dot[55][3],dis[2505][55];
int main()
{
    freopen("tower.in","r",stdin);
    freopen("tower.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&dot[i][1],&dot[i][2]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            cnt++;
            for(int k=1;k<=n;k++)
                dis[cnt][k]=abs(dot[k][1]-dot[i][1])+abs(dot[k][2]-dot[j][2]);
            sort(dis[cnt]+1,dis[cnt]+1+n);
            for(int k=1;k<=n;k++)
                dis[cnt][k]+=dis[cnt][k-1];
        }
    for(int i=1;i<=n;i++)
    {
        int ans=INF;
        for(int j=1;j<=cnt;j++)
            ans=min(ans,dis[j][i]);
        printf("%d
",ans);
    }
    return 0;
}

T3 题意简述:求一棵树的最大匹配及最大匹配种类数。

             60%的数据:答案不超过10^18。100%的数据:N≤1000。

   解题思路:先得吐槽一下出题人...模拟赛出什么高精度...听AK大佬说普通的高精还过不了,得用

             压位高精什么的...垃圾出题人

             以下思路及代码仅适用于前60分。

             考虑到匈牙利算法无法算出种类数,考虑树上算法。

             扳了扳手指算了算发现这次考试还没有考dp,考虑树形dp。

             f[i][0,1]表示以i为根的子树,f[i][0]表示点i未匹配的最大值,f[i][1]表示点i匹配

             的最大值,g[i][0,1]表示相应的方案数。

             f[i][0] = ∑max{f[i.son][0],f[i.son][1]}

                         g[i.son][0]            (f[i.son][0] > f[i.son][1])

             g[i][0] = ∏g[i.son][1]            (f[i.son][0] < f[i.son][1])

                         g[i.son][0]+g[i.son][1](f[i.son][0] == f[i.son][1])

             f[i][1] = max{f[i][0] - max(f[i.son][0],f[i.son][1]) + f[i.son][0]}+1

             g[i][1] = f[i][1]时的方案数。

             由于博主本人过菜,代码无法输出正确答案,这里贴出Menteur_Hxy大佬的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,cnt,root,d[1005],head[1005];
ll f[1005][2],g[1005][2];
struct uio{
    ll nxt,to;
}edge[1000005];
void add(ll x,ll y)
{
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
void dfs(ll x)
{
    ll sum=0,mul=1;
        for(ll i=head[x];i;i=edge[i].nxt) { ll y=edge[i].to;
        dfs(y); 
        sum+=max(f[y][0],f[y][1]);
        if(f[y][0]>f[y][1]) mul*=g[y][0];
        else if(f[y][0]<f[y][1]) mul*=g[y][1];
        else mul*=(g[y][0]+g[y][1]);
    }
    f[x][0]=sum,g[x][0]=mul;
    for(ll i=head[x];i;i=edge[i].nxt) { ll y=edge[i].to;
        ll now=sum-max(f[y][0],f[y][1])+f[y][0]+1;
        if(now>f[x][1]) {
            f[x][1]=now;
            if(f[y][0]>f[y][1]) g[x][1]=mul;
            else if(f[y][0]<f[y][1]) g[x][1]=mul/g[y][1]*g[y][0];
            else g[x][1]=mul/(g[y][0]+g[y][1])*g[y][0];
        } else if(now==f[x][1]) {
            if(f[y][0]>f[y][1]) g[x][1]+=mul;
            else if(f[y][0]<f[y][1]) g[x][1]+=mul/g[y][1]*g[y][0];
            else g[x][1]+=mul/(g[y][0]+g[y][1])*g[y][0];
        }    
    }
//    g[x][0]=1;f[x][0]=0;
//    for(ll i=head[x];i;i=edge[i].nxt)
//    {
//        ll y=edge[i].to;
//        dfs(y);
//        f[x][0]+=max(f[y][0],f[y][1]);
//        if(f[y][0]>f[y][1]) g[x][0]*=g[y][0];
//        if(f[y][0]<f[y][1]) g[x][0]*=g[y][1];
//        if(f[y][0]==f[y][1]) g[x][0]*=(g[y][0]+g[y][1]);
//    }
//    for(ll i=head[x];i;i=edge[i].nxt)
//    {
//        ll y=edge[i].to;
//        ll now=f[x][0]-max(f[y][0],f[y][1])+f[y][0]+1;
//        if(now>f[x][1])
//        {
//            f[x][1]=now;
//            if(f[y][0]>f[y][1]) g[x][1]=g[x][0];
//            if(f[y][0]<f[y][1]) g[x][1]=g[x][0]/g[y][1]*g[y][0];
//            if(f[y][0]==f[y][1]) g[x][1]=g[x][0]/(g[y][0]+g[y][1])*g[y][0];
//        }
//        if(now==f[x][1])
//        {
//            if(f[y][0]>f[y][1]) g[x][1]+=g[x][0];
//            if(f[y][0]<f[y][1]) g[x][1]+=g[x][0]/g[y][1]*g[y][0];
//            if(f[y][0]==f[y][1]) g[x][1]+=g[x][0]/(g[y][0]+g[y][1])*g[y][0];
//        }
//    }
}
int main()
{
//    freopen("tree.in","r",stdin);
//    freopen("tree.out","w",stdout);
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        ll u,v,w;
        scanf("%lld%lld",&u,&v);
        for(ll j=1;j<=v;j++)
        {
            scanf("%lld",&w),
            add(u,w);d[w]++;
        }
    }
    for(ll i=1;i<=n;i++)
        if(!d[i]) {root=i;break;}
    dfs(root);
    printf("%lld
",max(f[root][0],f[root][1]));
    if(f[root][0]>f[root][1]) printf("%lld
",g[root][0]);
    if(f[root][0]<f[root][1]) printf("%lld
",g[root][1]);
    if(f[root][0]==f[root][1]) printf("%lld
",g[root][0]+g[root][1]);
    return 0;
}
原文地址:https://www.cnblogs.com/water-radish/p/9354902.html