A层邀请赛1

A. Race

容易想到tire树,也容易想到判断两数大小关系在于第一个不同的二进制位

一个重要的点(我没想到):积分相当于排在它前面的人构成的点对数

通过在tire树上取反向size可以得到O(nm3)的做法,然后展开一下式子,或者观察一下二进制数,

展开平方得到一堆a2+b2+....+2ab+2ac....

当一个点对i,j存在,其实是这两个二进制位都为特定数,有2(m2)个数,而平方展开系数为2,所以这部分系数为2m1

而平方项显然也是2m1,所以一个简单的Tiredp即可

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 200005;
const int mod = 1e9 + 7;
typedef long long ll;
int n, m, a[maxn], mc;
ll score[maxn],ans;
int tong[30];
struct tire{
    int ch[maxn * 31][2], node = 1, ls[33], root = 1, cnt[maxn * 31];
    void add(int x){
        for(int i = 0; i < m; ++i)ls[i] = (bool) (x & (1 << i));
        int now = root;
        for(int i = m - 1; i >= 0; --i){
            if(!ch[now][ls[i]])ch[now][ls[i]] = ++node;
            now = ch[now][ls[i]];
            ++cnt[now];
        }
    }
    int id, tot;
    void dfs(int now, int dep, ll sum, ll ans){
        if(dep == 0)score[++id] = ans * (1 << (m - 1)) % mod;
        int lc = ch[now][0], rc = ch[now][1];
        if(lc)dfs(lc, dep - 1,(sum + cnt[rc]) % mod, (ans + cnt[rc] * (sum + cnt[rc]) % mod) % mod);
        if(rc)dfs(rc, dep - 1,(sum + cnt[lc]) % mod, (ans + cnt[lc] * (sum + cnt[lc]) % mod) % mod);
    }
}T;
int main(){
    scanf("%d%d", &n, &m);mc = (1 << m);
    for(int i = 1; i <= n; ++i)scanf("%d", &a[i]);
    sort(a + 1, a + n + 1);
    for(int i = 1; i <= n; ++i)T.add(a[i]);
    T.dfs(1, m, 0, 0);
    for(int i = 1; i <= n; ++i)ans = ans xor (score[i] % mod);
    for(int i = 1; i <= n; ++i)score[i] = (score[i] + 1ll * (n - i) * (n - i) % mod) % mod;
    printf("%lld\n", ans);
    return 0;
}

B. 青蛙

这种乱搞贪心题我怎么不敢猜了呢

有一说一,用二分的正解我想到了,但是不觉得正确。。。。。

找出尽可能多条免费道路,记条数为cnt

cnt==0用最小的挨个跳完全程,其他的直接跳n

cnt!=0用最大的cnt个跳免费的,剩余格子显然能免费跳完,剩下的直接跳到n

如何找cnt

可以用set维护a,每次找距离 <=d 的最大的那个跳,正确性不会证。。

更优秀的做法是双指针,每次尽可能让左指针跳到右指针,可以发现这样不会使答案更劣,比上面的做法少一个log,并且正确性显然

code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 55;
int n, m, k, d, c[maxn], a[maxn], f[maxn];
void work(){
    scanf("%d%d%d%d", &n, &m, &k, &d);
    for(int i = 1; i <= m; ++i)scanf("%d", &c[i]);
    for(int i = 1; i <= k; ++i)scanf("%d", &a[i]);
    sort(a + 1, a + k + 1); sort(c + 1, c + m + 1);
    int p = 1, cnt = 0;
    for(int i = 0 ; i <= k ; ++i)f[i] = 0;
    for(; p <= k; ++p)if(a[p] - 1 <= d)f[p] = 1;else break;
    for(int i = 1; i <= k; ++i)if(f[i] && a[p] - a[i] <= d && p <= k)f[p] = 1, f[i] = 0, ++p;
    for(int i = k; i >= 1; --i)if(n - a[i] <= d && f[i]) ++cnt;else break;
    ll ans = 0;
    if(cnt == 0){
        a[0] = 1; a[k + 1] = n;
        for(int i = 1; i <= k + 1; ++i)if(a[i] - a[i - 1] > d)ans += c[1];
        ans -= c[1];
    }
    for(int i = 1; i <= m - cnt; ++i)ans = (ans + c[i]);
    cerr<< cnt << endl;
    printf("%lld\n",ans);
}
signed main(){
    int t;scanf("%d",&t);
    for(int ask = 1; ask <= t; ++ask)work();
    return 0;
}

C. 序列

吉司机线段树板子,对取max操作,线段树上维护区间最小值和严格次小值,如果取max的数小于最小值,就不用管,大于次小值继续递归,在两个值之间只修改最小值

剩下的就是码了

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int n, m, a[maxn],val[maxn];
char c[3];
struct node{ll val; int op;}ans;
struct tree{
    struct node{
        ll dt, mi, cmi;
        int ctmi, ctdt;
    }t[maxn << 2 | 1];
    void push_up(int x){
        int ls = x << 1, rs = x << 1 | 1;
        if(t[ls].mi < t[rs].mi){
            t[x].mi = t[ls].mi;
            t[x].cmi = t[ls].cmi;
            t[x].cmi = min(t[x].cmi, t[rs].mi == t[x].mi ? inf : t[rs].mi);
            t[x].cmi = min(t[x].cmi, t[rs].cmi == t[x].mi ? inf : t[rs].cmi);
        }else{
            t[x].mi = t[rs].mi;
            t[x].cmi = t[rs].cmi;
            t[x].cmi = min(t[x].cmi, t[ls].mi == t[x].mi ? inf : t[ls].mi);
            t[x].cmi = min(t[x].cmi, t[ls].cmi == t[x].mi ? inf : t[ls].cmi);
        }
    }
    void built(int x, int l, int r){
        if(l == r){t[x].mi = val[l]; t[x].cmi = inf;return;}
        int mid = (l + r) >> 1;
        built(x << 1, l , mid);
        built(x << 1 | 1, mid + 1, r);
        push_up(x);
    }
    void push_down(int x){
        int ls = x << 1, rs = x << 1 | 1;
        if(t[x].ctdt){
            t[ls].ctdt += t[x].ctdt;
            t[rs].ctdt += t[x].ctdt;
            t[ls].dt += t[x].dt;
            t[rs].dt += t[x].dt;
            t[ls].mi += t[x].dt;
            t[rs].mi += t[x].dt;
            t[ls].cmi += t[x].dt;
            t[rs].cmi += t[x].dt;
            t[x].dt = 0;
            t[x].ctdt = 0;
        }
        if(t[x].ctmi){
            if(t[ls].mi < t[x].mi){
                t[ls].ctmi += t[x].ctmi;
                t[ls].mi = t[x].mi;
            }
            if(t[rs].mi < t[x].mi){
                t[rs].ctmi += t[x].ctmi;
                t[rs].mi = t[x].mi;
            }
            t[x].ctmi = 0;
        }
    }
    void modify_add(int x, int l, int r, int L, int R, int dt){
        if(L <= l && r <= R){
            t[x].mi += dt;
            t[x].cmi += dt;;
            t[x].dt += dt;
            ++t[x].ctdt;
            return;
        }
        push_down(x);
        int mid = (l + r) >> 1;
        if(L <= mid)modify_add(x << 1, l, mid, L, R, dt);
        if(R > mid)modify_add(x << 1 | 1, mid + 1, r, L, R, dt);
        push_up(x);
    }
    void query(int x, int l, int r, int pos){
        if(l == r){
            ans.val = t[x].mi;
            ans.op = t[x].ctmi + t[x].ctdt;
            return;
        }
        push_down(x);
        int mid = (l + r) >> 1;
        if(pos <= mid)query(x << 1, l, mid, pos);
        else query(x << 1 | 1, mid + 1, r, pos);
    }
    void modify_min(int x, int l, int r, int L, int R, int dt){
        if(L <= l && r <= R){
           if(t[x].mi >= dt)return;
           if(t[x].cmi > dt){
               t[x].mi = dt;
               ++t[x].ctmi;
               return;
           }
        }
        push_down(x);
        int mid = (l + r) >> 1;
        if(L <= mid)modify_min(x << 1, l, mid, L, R, dt);
        if(R > mid)modify_min(x << 1 | 1, mid + 1, r, L, R, dt);
        push_up(x);
    }
}T;
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)scanf("%d", &val[i]);
    T.built(1, 1, n);
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i){
        scanf("%s",c);
        if(c[0] == 'Q'){
            int pos; scanf("%d", &pos);
            T.query(1, 1, n, pos);
            printf("%lld %d\n",ans.val, ans.op);
        }else{
            int l, r, dt;scanf("%d%d%d",&l,&r,&dt);
            if(c[0] == 'A' && dt)T.modify_add(1, 1, n, l, r, dt);
            if(c[0] == 'M')T.modify_min(1, 1, n, l, r, dt);
        }
    }
    return 0;
}
posted @   Chen_jr  阅读(32)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示