牛客小白月赛22

操作序列

思路

这题我觉得用map模拟其实很好,但是如果用线段树的话也还行,主要是线段树不是很会。

为了避免不必要的开销,map使用find函数,打印的时候用map.begin()->second就可以了啦。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
int main()
{
    map<ll,ll> mp;
    int n;
    scanf("%d",&n);
    char ch;
    ll num1,num2;
    while (n--) {
        scanf("%lld%c",&num1,&ch);
        if (ch==' ') {
            scanf("%lld",&num2);
            bool flag=true;
            for (int i=num1-30;i<=num1+30;i++) {
                if (mp.find(i)!=mp.end()) {
                    flag=false;
                    break;
                }
            }
            if (flag) {
                mp[num1]=num2;
            }
        }
        else {
            if (num1==-1) {
                if (mp.begin()!=mp.end()) {
                    printf("%lld\n",mp.begin()->second);
                    mp.erase(mp.begin());
                }
                else {
                    printf("skipped\n");
                }
            }
            else {
                if (mp.find(num1)==mp.end()) {
                    printf("0\n");
                }
                else {
                    printf("%lld\n",mp[num1]);
                }
            }
        }
    }
    return 0;
}

树上子链

思路

这题他们说是树形dp模板题,定义dp[i]是以i为根节点,不同时携带左右子树的值最大链。

这样对于每一个根节点就可以判断加上左右子树之后的最大值了。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1e5+10;
vector<int> g[maxn];
int w[maxn];
ll dp[maxn],ans=-(1<<30);

void dfs(int u,int f) {
    dp[u]=w[u];
    for (auto v:g[u]) {
        if (v==f) {
            continue;
        }
        dfs(v,u);
        ans=max(ans,dp[u]+dp[v]);
        dp[u]=max(dp[u],dp[v]+w[u]);
    }
    ans=max(ans,dp[u]);
}
int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++) {
        scanf("%d",&w[i]);
    }
    int u,v;
    for (int i=0;i<n-1;i++) {
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0);
    printf("%lld\n",ans);
    return 0;
}

货物种类

思路

这题就是暴力啦,所有点做排列,10!是3e6左右,10组问题不大。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
int x[15],y[15],a[15];
inline int getDistance(int i,int j) {
    return abs(x[i]-x[j])+abs(y[i]-y[j]);
}

int main()
{
    int t;
    scanf("%d",&t);
    while (t--) {
        int sx,sy;
        scanf("%d%d",&sx,&sy);
        scanf("%d%d",&sx,&sy);
        int n;
        scanf("%d",&n);
        for (int i=0;i<n;i++) {
            scanf("%d%d",&x[i],&y[i]);
            a[i]=i;
        }
        a[n]=n;
        x[n]=sx;
        y[n]=sy;
        int ans=1<<30;
        do {
            int c=getDistance(a[0],n)+getDistance(a[n-1],n);
            for (int i=0;i<n-1;i++) {
                // printf("%d %d %d    ",a[i],a[i+1],getDistance(a[i],a[i+1]));
                c+=getDistance(a[i],a[i+1]);
            }
            // printf("\n%d\n",c);
            ans=min(ans,c);
        } while (next_permutation(a,a+n));
        printf("The shortest path has length %d\n",ans);
    }
    return 0;
}

仓库选址

思路

这题暴力都能过,没错就是你想的暴力,n^4,但是这题正解应该包括有前缀和和数学两种解法。

前缀和就很简单啦。

先求出来第一列,所有行的答案,然后递推其他点的答案。

关于递推,假设当前点是(x,y) ,下一个点是(x,y+1),则矩阵[m,x] (右上角的点,左下角(1,1))中的每个点到(x,y+1)的x距离都+1,但是y距离不变;矩阵[x+1,1]到[m,n]中的每个点x的距离都减一。

当我们知道(x,y)的答案之后,左边的矩阵总共需要走几次就加几,右边的矩阵需要走几次就减几就可以啦。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=105;
ll a[maxn][maxn],sum[maxn][maxn],cnt[maxn][maxn],c[maxn][maxn];
int main()
{
    ll t;
    scanf("%lld",&t);
    while (t--) {
        ll n,m;
        scanf("%lld%lld",&n,&m);
        for (ll i=1;i<=m;i++) {
            for (ll j=1;j<=n;j++) {
                scanf("%lld",&a[i][j]);
            }
        }
        for (ll i=1;i<=m;i++) {
            for (ll j=1;j<=n;j++) {
                cnt[i][j]=cnt[i][j-1]+cnt[i-1][j]-cnt[i-1][j-1]+a[i][j];
                a[i][j]=a[i][j]*(abs(i-1)+abs(j-1));
                sum[i][j]=sum[i][j-1]+sum[i-1][j]+a[i][j]-sum[i-1][j-1];
            }
        }
        c[1][1]=sum[m][n];
        ll ans=min((ll)(1<<30),c[1][1]);
        for (ll i=2;i<=m;i++) {
            c[i][1]=c[i-1][1]-(cnt[m][n]-cnt[i-1][n])+cnt[i-1][n];
            ans=min(c[i][1],ans);
        }
        for (ll i=1;i<=m;i++) {
            for (ll j=2;j<=n;j++) {
                c[i][j]=c[i][j-1]-(cnt[m][n]-cnt[m][j-1])+cnt[m][j-1];
                ans=min(c[i][j],ans);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-03-03 13:36  xyee  阅读(172)  评论(0编辑  收藏  举报