Codeforces Round #765 (Div. 2)

Posted on 2022-01-21 17:47  Capterlliar  阅读(61)  评论(0)    收藏  举报

C. Road Optimization

题意:路上有很多标牌,路过这个标牌后,你每走一个单位长度的时间变为标牌上的数字。现在你可以忽视k个标牌,求从0走到 l 最少所需的时间。

解:是个dp。先套路地设 dp[i][j] 表示走到第 i 个标牌,忽视掉 j 个标牌所需的最短时间,好,考虑转移。加进来一个新的,考虑从前一个距离怎么变到现在的距离。已知新走一段的速度和前一个路牌有关,但我不确定前一个路牌有没有被我删掉。把速度写进状态里显然不好,有boom的风险。那就以前面每一个为起点开始走,取最小值。现在 j 定义为忽视,但从一个起点开始走是选择了这块路牌的意思,很别扭。不如把 j 定义为选择了 j 个路牌,最后减一下,就好写了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 505
#define eps 0.00000001
#define inf 0x7fffffff
//#define int long long
int n,l,k;
int d[maxx]={0},a[maxx]={0};
int dp[maxx][maxx]={0};
signed main() {
//    int T;
//    scanf("%d",&T);
//    while(T--){
//
//    }
    scanf("%d%d%d",&n,&l,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&d[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=n+1;j++)
            dp[i][j]=inf;
    a[n+1]=0;d[n+1]=l;dp[1][1]=0;
    for(int i=2;i<=n+1;i++){
        for(int j=1;j<=i;j++){
            for(int s=1;s<=i-1;s++){
                if(dp[s][j-1]!=inf)
                    dp[i][j]=min(dp[i][j],dp[s][j-1]+a[s]*(d[i]-d[s]));
            }
        }
    }
    int ans=inf;
    for(int i=n+1;i>=n+1-k;i--)
        ans=min(ans,dp[n+1][i]);
    printf("%d\n",ans);
    return 0;
}
//dp[i][j]=dp[start][j-1]+a[start]*(d[i]-d[start]);
//dp[i][j]  到第i个点,选择了j个点   j<=i
View Code

D. Binary Spiders

这题配图真是充满灵性,要我真看到14腿蜘蛛能吓飞出去 

题意:给出n个数,选择其最大子集,使得子集内的数两两异或值大于等于k。

解:首先观察一下。如果比k大的位上有1,那答案肯定比k大(废话。0和1不同能产生1,因此在比k大的某一位上,所有数分成两拨,一拨是0,一拨是1。同一拨里根据下一位再分成两拨,就这样分到k的最高位。对于和k相同的位里,如果k这一位是1,那还要继续分成两拨;如果是0,那就不用分了,随便挑俩当答案。

看起来像个递归,还是个巨难写的递归。但真的有大佬写出来了,膜一下%%%     点击就膜

然后继续观察。对于任意大于0的k,其高于最高位的部分能分成2的某次幂拨。但由于数只有n个,所有不会炸。由于抽屉原理,在每一拨里最多选俩数。那问题就变成了从每一拨里选两个数,其异或值大于等于k。这里学了个新技能,01trie求最大异或值,复杂度nlogc,相当舒服xxx

第一次板子有点问题,第二个就好了,而且清零清得很优雅,一点也不T。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 300005
#define eps 0.00000001
#define inf 0x7fffffff
//#define int long long
    int son[maxx<<5][2],idx;
    void init() {
        memset(son, 0, sizeof (int) * 2 * idx);
        idx = 0;
    }
    void insert(int x) {
        int cur = 0;
        for (int i = 30; i >= 0; i --) {
            int &to = son[cur][x >> i & 1];
            to ?: to = ++ idx;
            cur = to;
        }
    }
    int query(int x) {
        int cur = 0, ans = 0;
        for (int i = 30; i >= 0; i --) {
            int to = son[cur][~ x >> i & 1];
            to ? ans += 1 << i, cur = to : cur = son[cur][x >> i & 1];
        }
        return ans;
    }
int n,k;
int a[maxx];
map<int,int> m1;
map<int,vector<int> > group;
vector<int> ans;
signed main() {
//    int T;
//    scanf("%d",&T);
//    while(T--){
//
//    }
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        m1[a[i]]=i;
    }
    if(k==0){
        printf("%d\n",n);
        for(int i=1;i<=n;i++)
            printf("%d ",i);
        return 0;
    }
    int length=0,b=k;
    while(b){
        b/=2;
        length++;
    }
    for(int i=1;i<=n;i++){
        int t=a[i]>>length;
        group[t].push_back(a[i]);
    }
    for(auto [i,vec]:group){
        init();
        int res=0;
        for(int x:vec){
            insert(x);
            int y=query(x);
            res=max(res,y);
            if(y>=k){
                ans.push_back(m1[x]);
                ans.push_back(m1[x^y]);
                break;
            }
        }
        if(res<k)
            ans.push_back(m1[vec[0]]);
    }
    if(ans.size()<2){
        printf("-1\n");
        return 0;
    }
    sort(ans.begin(),ans.end());
    printf("%d\n",ans.size());
    for(auto i:ans)
        printf("%d ",i);
    return 0;
}
View Code