校内模拟赛(三)(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\n",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\n",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

猜你喜欢

转载自www.cnblogs.com/Hale522520/p/11590380.html