Codeforces Round #436 (Div. 2)E,F详解

鉴于太多人把D做出来了,实际上D就是道模拟简单题,所以本篇博客并没有D的题解。如果有需要的读者可以联系博主,博主会很热心的为你解释的(笑)。。
E题题解:Polycarp家着火了。。他家里有n个值钱的东西,每一个东西有一个营救需要的时间和一个烧毁需要的时间。问Polycarp能救出的东西的最大价值为多少,并输出营救顺序。
思路:裸的01背包问题。。如果不明白01背包问题可以看看紫书的动规专题。
思路出来了,博主觉得有必要讲的两点就是,一,它和01背包问题唯一不同的是有一个限制时间,不像01背包啥时候都可以拿,它拿某个物品的时间是一段区间。二,能拿某个物品的时间怎么算,首先状态转移方程式为
dp[T]=max(dp[T],dp[T-t[i]]+w[i]),显然T< d[i],并且T>t[i].所以只会更新该区间的值,但更新完了肯定会影响后面的T(从这个式子就可以看出),所以为了复杂度低(你也可以更新后面的T,加个判断即可),首先把物品按照d排个序,先取小的,再取大的,这样就可保证再更新大的时候小的已经全部被更新了。
代码如下:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node
{
    int t, d, p;
    int idx;
    bool operator<(const node &b)const
    {
        return d < b.d;
    }
}nodes[205];
vector<int>V[2005];
int dp[2005];
int main()
{
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++)
    {
        scanf("%d%d%d", &nodes[i].t, &nodes[i].d, &nodes[i].p);
        nodes[i].idx = i;
    }
    sort(nodes + 1, nodes + 1 + n);
    for(int i=1;i<=n;i++)
        for (int j = nodes[i].d - 1;j >= nodes[i].t;j--)
        {
            if (dp[j] < dp[j - nodes[i].t] + nodes[i].p)
            {
                dp[j] = dp[j - nodes[i].t] + nodes[i].p;
                V[j] = V[j - nodes[i].t];
                V[j].push_back(nodes[i].idx);
            }
        }
    int theans = 0;
    int idx=-1;
    for(int i=0;i<=2000;i++)
        if (theans < dp[i])
        {
            theans = dp[i];
            idx = i;
        }
    cout << theans << endl;
    if (idx == -1)
    {
        cout << 0 << endl;
        return 0;
    }
    int Size = V[idx].size();
    cout << Size << endl;
    for (int i = 0;i < Size;i++)
    {
        if (i != 0)printf(" ");
        printf("%d", V[idx][i]);
    }
    return 0;
}

F题题意:给你一个图,有q次询问,从s到t的结点最小字典序路径中的第k个结点是谁。
思路:这题好啊,让博主学习到了图上的倍增。另外也让博主领悟到了一个小套路,即如果题目给你一个k,让你求路径上的第k个点,这大概就需要用倍增的思想了。
思路挺简单的,那么如何用倍增呢?请读者仔细看代码,并理解从中倍增的奥妙和如何用倍增判断是环的。

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 3005;
const int maxq = 4e5 + 10;
vector<int>G[maxn], TO[maxn];
vector < pair<pair<int, int>, int>>Q[maxq];
bool vis[maxn];
#define MP(x,y) make_pair(x,y)

void dfs(int node)
{
    if (vis[node])return;
    vis[node] = 1;
    for (int i : TO[node])
        dfs(i);
}
int st[maxn][13];
int ans[maxq];
int main()
{
    int n, m, q;
    cin >> n >> m >> q;
    int u, v;
    for (int i = 1;i <= m;i++)
    {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        TO[v].push_back(u);
    }
    int s, t, k;
    for (int i = 1;i <= q;i++)
    {
        scanf("%d%d%d", &s, &t, &k);
        Q[t].push_back(MP(MP(s, k), i));
    }
    for (int i = 1;i <= n;i++)sort(G[i].begin(), G[i].end());
    for (int i = 1;i <= n;i++)if(Q[i].size())
    {
        memset(vis, 0, sizeof(vis));
        dfs(i);
        memset(st, 0, sizeof(st));
        for (int j = 0;j < 13;j++)st[n + 1][j] = n + 1;
        for (int j = 1;j <= n;j++)
        {
            if (j == i)st[j][0] = n + 1;
            else if (vis[j])
            {
                for (int v : G[j])
                {
                    if (!vis[v])continue;
                    st[j][0] = v;
                    break;
                }
            }
        }
        for (int j = 1;j < 13;j++)
            for (int u = 1;u <= n;u++)if(vis[u])
                st[u][j] = st[st[u][j - 1]][j - 1];
        for (auto it : Q[i])
        {
            int s = it.first.first;
            int k = it.first.second - 1;
            int id = it.second;
            if (vis[s])
            {
                if (st[s][12] == n + 1)
                {
                    for (int j = 0;j < 13;j++)
                        if (k&(1 << j))
                            s = st[s][j];
                    if (s != n + 1)
                        ans[id] = s;
                    else
                        ans[id] = -1;
                }
                else
                    ans[id] = -1;
            }
            else
            {
                ans[id] = -1;
            }

        }
    }

    for (int i = 1;i <= q;i++)
        cout << ans[i] << endl;
    return 0;

}

代码浑然天成啊。。。博主想解释为啥用离线,但感觉没必要,因为都这样写了,还能用在线不成。希望读者仔细阅读代码,学会了又有新姿势上分了~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值