Codeforces Round #367/706 (Div. 2)

借别人账号提交,多年没打cf,感觉智商上线?

A. Beru-taxi

给定人的坐标、n个出租车坐标和速度,出租车会按照这个速度向人开来,求最快什么时候能上到车。

代码找不到了,反正就是水题,暴力全部车子求距离/速度就行了,略

B. Interesting drink

C. Hard problem

给n个字符串和每个字符串反转一次需要的代价,求最小代价使得这n个字符串按字典序排列(字符串相同也认为是符合字典序),无解输出-1。
我们一直保持前i个字符串有序,dp搞就行了。

dp[i][0] : 当前字符串不旋转的情况下符合前i个字符串有序的最小代价;
dp[i][1] : 当前字符串旋转的情况下符合前i个字符串有序的最小代价。

dp[i][0] = min(dp[i-1][0],dp[i-1][1]) | str[i-1] < str[i]
dp[i][1] = cost[i] + min(dp[i-1][0],dp[i-1][1]) | str[i-1] < str[i]
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define clr( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
const int maxn = 100005;
const ll inf = 92233720368547807LL;
int val[maxn];
string s1[maxn];
ll dp[maxn][2];
int main() {
    int n;

    while (cin >> n) {
        clr(val, 0);
        for (int i = 1; i <= n; ++i) {
            cin >> val[i];
        }
        for (int i = 1; i <= n; ++i) {
            cin >> s1[i];
        }
        dp[1][0] = 0;
        dp[1][1] = val[1];
        dp[n][0] = dp[n][1] = inf;
        for (int i = 2; i <= n; ++i) {
            ll mx = inf;
            if (s1[i - 1] <= s1[i]) {
                mx = min(dp[i - 1][0], mx);
            }
            string last = s1[i - 1];
            reverse(last.begin(), last.end());
            if (last <= s1[i]) {
                mx = min(dp[i - 1][1], mx);
            }
            dp[i][0] = mx;


            ll my = inf;
            string cur = s1[i];
            reverse(cur.begin(), cur.end());
            if (s1[i - 1] <= cur) {
                my = min(val[i] + dp[i - 1][0], my);
            }
            if (last <= cur) {
                my = min(val[i] + dp[i - 1][1], my);
            }
            dp[i][1] = my;
            // cout << dp[i][0] << " " << dp[i][1] << endl;
        }
        ll ans = min(dp[n][0], dp[n][1]);
        if (ans == inf) {
            cout << "-1" << endl;
        } else {
            cout << ans << endl;
        }
    }
    return 0;
}

D. Hard problem

给一个元素可重复的集合,初始有一个0元素在里面,现有三种操作(20W次):
1. + x 集合增加一个元素x
2. - x 集合删除一个元素x,数据保证删除时一定至少有一个x
3. ? x 查询集合元素和x的最大异或值,即
关键在于查询操作,我们不能直接遍历集合,现我们采用字典树+贪心可解决。

这题是 POJ 3764 的简化版,POJ的题解戳我

解:建一棵只有0和1的字典树,每加一个元素就将它按二进制插入树中,查询x时按二进制高位到低位求找树上点,为了使异或结果最大,我们总选择跟x的当前位值相反的点(异或不同时才为1,这样高位尽可能大总结果也就自然大),边找边把该结点的值累计上去就行了。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define clr( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);

const int maxm = 4000100;   //结点个数

struct node
{
    int time;
    int next[2];        //保存编号
    void init() {
        clr(next, 0);  //0表示不存在结点,其他数字为编号
        time = 0;
    }
} node[maxm];
int cnt,tol;
void add(int x)
{
    int u = 0, idx;
    for (int i = 30; i >= 0; i--)
    {
        if ((1 << i) & x)  idx = 1; else idx = 0; //该位数字
        if (!node[u].next[idx])     //不存在就新建
        {
            node[u].next[idx] = ++tol;
            node[tol].init();
        }
        u = node[u].next[idx];      //往下走
        node[u].time++;
    }
}

void del(int x)
{
    int u = 0, idx;
    for (int i = 30; i >= 0; i--)
    {
        if ((1 << i) & x)  idx = 1; else idx = 0;
        u = node[u].next[idx];
        node[u].time--;
    }
}

int query(int x)    //查询树上点跟x的异或最大值
{
    int u = 0, res = 0, idx;
    for (int i = 30; i >= 0; i--)
    {
        if ((1 << i)&x) idx = 1; else idx = 0;
        if (node[u].next[!idx] && node[node[u].next[!idx]].time > 0)    //相反数且有次数
        {
            u = node[u].next[!idx];
            res |= (1 << i);       //加上路径上的值
        } else   u = node[u].next[idx];
    }
    return res;     //求x^res最大跟求res最大一样
}

int main()
{
    // RE
    int n;
    char op; int y;
    scanf("%d%*c", &n);
    tol = 0;cnt = 0;
    node[0].init();
    add(0);

    for (int i = 0; i < n; ++i) {
        scanf("%c %d%*c", &op, &y);
        if (op == '+') {
            add(y);
        } else if (op == '-') {
            del(y);
        } else if (op == '?') {
            printf("%d\n", query(y));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u012469987/article/details/52193739