首页 > 编程语言 >第二十届西南科技大学ACM程序设计竞赛(同步赛)

第二十届西南科技大学ACM程序设计竞赛(同步赛)

时间:2024-06-09 17:37:30浏览次数:23  
标签:第二十届 int ll ACM add ans 程序设计 糖果 void

第二十届西南科技大学ACM程序设计竞赛(同步赛)

A:异或症

题意:给定一个排列,选任意i, j,使得 pi = pi ^ j,最后求前缀异或数组,求这个数组的最大和

思路:发现可以把所有数变成出现过的二进制位的和

void solve(){
    ll n;
    cin >> n;
    map<ll, ll> mp;
    for(int i = 1; i <= n; i ++){
        ll x;
        cin >> x;
        for(int i = 0; i <= 40; i ++){
            if(x >> i & 1){
                mp[1ll << i] = 1;
            }
        }
    }
    ll ans = 0;
    for(auto [x, y] : mp) ans += x;
    ans *= n;
    cout << ans << '\n';
}

B:拾取糖果

题意:直角坐标平面上有 n 个糖果,糖果都处于整数点上,求任意一条通过原点的直线最多可以经过几个糖果

思路:对坐标除以 gcd 即可,注意特判一下在坐标轴上和原点的糖果即可

void solve(){
    ll n;
    cin >> n;
    map<PLL, ll> mp;
    ll ze = 0;
    for(int i = 1; i <= n; i ++){
        ll x, y;
        cin >> x >> y;
        if(x == 0 && y == 0){
            ze ++;
            continue;
        }
        else if(x == 0){
            mp[{0, 1}] ++;
            continue;
        }
        else if(y == 0){
            mp[{1, 0}] ++;
            continue;
        }
        ll gd = __gcd(x, y);
        x /= gd;
        y /= gd;
        mp[{x, y}] ++;
    }    
    ll ans = 0;
    for(auto [x, y] : mp) ans = max(ans, y + ze);
    cout << ans << '\n';
}

C:图腾

题意:长度为 n 的数轴上有 m 个图腾,每个点的能量为左边最近的图腾的能量 * 右边最近的图腾的能量,q 次操作,插入图腾或者求区间内点的能量值的和

思路:线段树维护即可,倒过来看作每次删除图腾,预处理每个点的左边的图腾和右边的图腾,每次删除图腾就修改 pre + 1 ~ i - 1,i ~ i,i + 1 ~ nxt - 1,这三个区间即可,线段树维护一下区间和

struct Node{
    ll sum, siz;
    ll add;
};
struct segtree{
    ll n;
    vector<Node> a;
    segtree(ll _n) : n(_n * 4 + 10), a(n + 1) {}
    void pushup(ll u){
        a[u].sum = a[u * 2].sum + a[u * 2 + 1].sum;
    }
    
    void eval(Node & t, ll add){
        t.sum = t.sum + add * t.siz;
        t.add = t.add + add;
    }
    
    void pushdown(ll u){
        eval(a[u * 2], a[u].add);
        eval(a[u * 2 + 1], a[u].add);
        a[u].add = 0;
    }
    
    void build(ll u, ll l, ll r, vector<ll> & arr){
        if(l == r){
            a[u] = {arr[l], 1, 0};
            return;
        }
        ll mid = l + r >> 1ll;
        a[u] = {0, r - l + 1, 0};
        build(u * 2, l, mid, arr);
        build(u * 2 + 1, mid + 1, r, arr);
        pushup(u);
    }
    
    void modify(ll u, ll l, ll r, ll l1, ll r1, ll add){
        if(l1 <= l && r <= r1) eval(a[u], add);
        else{
            pushdown(u);
            ll mid = l + r >> 1ll;
            if(l1 <= mid) modify(u * 2, l, mid, l1, r1, add);
            if(r1 > mid) modify(u * 2 + 1, mid + 1, r, l1, r1, add);
            pushup(u);
        }
    }
    ll query(ll u, ll l, ll r, ll l1, ll r1){
        if(l1 <= l && r <= r1) return a[u].sum;
        else{
            pushdown(u);
            ll mid = l + r >> 1ll;
            ll res = 0;
            if(l1 <= mid) res += query(u * 2, l, mid, l1, r1);
            if(r1 > mid) res += query(u * 2 + 1, mid + 1, r, l1, r1);
            return res;
        }
    }
};

ll n, m, q;

struct node{
    ll op, l, r;
};
void solve(){
    cin >> n >> m >> q;
    vector<ll> p(n + 1);
    vector<ll> x(m + 1), v(m + 1);
    for(int i = 1; i <= m; i ++) cin >> x[i];
    for(int i = 1; i <= m; i ++){
        cin >> v[i];
        p[x[i]] = v[i];
    }
    vector<node> now(q + 1);
    for(int i = 1; i <= q; i ++){
        ll op, l, r;
        cin >> op >> l >> r;
        now[i] = {op, l, r};
        if(op == 1){
            p[l] = r;
        }
    }
    vector<ll> ans;
    vector<ll> pre(n + 1), nxt(n + 1);
    vector<ll> he(n + 1);
    for(int i = 1, j = 0; i <= n; i ++){
        if(j != 0) pre[i] = j;
        if(p[i] != 0) j = i;
    }
    for(int i = n, j = 0; i >= 1; i --){
        if(j != 0) nxt[i] = j;
        if(p[i] == 0 && pre[i] && nxt[i]) he[i] = p[pre[i]] * p[nxt[i]];
        if(p[i] != 0) j = i;
    }
    
    segtree seg(n);//初始化线段树大小
    seg.build(1, 1, n, he);//建树,s是vector数组

    for(int i = q; i >= 1; i --){
        auto [op, l, r] = now[i];
        if(op == 1){
            ll pp = pre[l], qq = nxt[l];
            ll p1 = p[pp] * p[qq];
            seg.modify(1, 1, n, pp + 1, l - 1, p1 - seg.query(1, 1, n, l - 1, l - 1));
            seg.modify(1, 1, n, l + 1, qq - 1, p1 - seg.query(1, 1, n, l + 1, l + 1));
            seg.modify(1, 1, n, l, l, p1);
            nxt[pp] = qq;
            pre[qq] = pp;
        }
        else{
            ll res = seg.query(1, 1, n, l, r);
            ans.push_back(res);
        }
    }
    for(int i = ans.size() - 1; i >= 0; i --) cout << ans[i] << '\n';
}

D:能源

题意:n 个庇护所,每个庇护所需要 ai 的能源,有 m 个能提供 bi 能源的电池,求满足所有庇护所需求的同时最小的电池能源之和

思路:排序双指针即可

void solve(){
    ll n, m;
    cin >> n >> m;
    vector<ll> a(n + 1), b(m + 1);
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 1; i <= m; i ++) cin >> b[i];
    sort(a.begin() + 1, a.end());
    sort(b.begin() + 1, b.end());
    ll ans = 0;
    int i = 1, j = 1;
    for(i = 1, j = 1; i <= n && j <= m; i ++){
        while(j <= m && a[j] < a[i]) j ++;
        ans += a[j];
        j ++; 
    } 
    cout << ans << '\n';
}

E:又双叒叕分糖果

题意:两个糖果包分别有一些重量的糖果,丢掉每个糖果包一半数量的糖果,然后再从两个糖果剩余的糖果中选取糖果组成新的糖果包,新的糖果包中不能有相同重量的糖果,求新的糖果包最多能有几种不同重量的糖果

思路:先分别统计两个糖果包的糖果种类,种类相同的数量全部丢掉,如果丢掉了重复的还不够就从糖果种类中丢掉,求每个糖果包中能选几种糖果,同时记录一下两个糖果包都有的糖果,优先选掉各自独有的糖果种类,然后才从共有的糖果中选取

void solve(){
    ll n;
    cin >> n;
    ll x, y;
    cin >> x >> y;
    ll sum1 = 0, sum2 = 0;
    map<ll, ll> a, b, c1;
    
    for(int i = 1; i <= x; i ++){
        ll w, num;
        cin >> w >> num;
        sum1 += num - 1;
        a[w] ++;
    }
    for(int i = 1; i <= y; i ++){
        ll w, num;
        cin >> w >> num;
        sum2 += num - 1;
        b[w] ++;
        if(a.count(w)) c1[w] ++;
    }

    ll ans = 0;
    ll cha1 = 0, cha2 = 0;
    if(sum1 < n / 2) cha1 = n / 2 - sum1;
    if(sum2 < n / 2) cha2 = n / 2 - sum2;
    
    x -= cha1, y -= cha2;
    for(auto [c, d] : a){
        if(x <= 0) break;
        if(!c1.count(c)){
            x --;
            ans ++;
        }
    }
    for(auto [c, d] : b){
        if(y <= 0) break;
        if(!c1.count(c)){
            y --;
            ans ++;
        }
    }
    ll yu = x + y;
    ll get = min(yu, (ll)(c1.size()));
    ans += get;
    cout << ans << '\n';
}

J:再聚端午,祝全体老师、同学、志愿者们,端午安康!

题意:四个点,A-B-C-D-A,求总路程

思路:一个求距离函数,调用即可

double dist(double x1, double y1, double x2, double y2){
    double ans = 0;
    ans = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
    ans = sqrt(ans);
    return ans;
}
void solve(){
    vector<double> x(5), y(5);
    for(int i = 1; i <= 4; i ++){
        cin >> x[i] >> y[i];
    }
    double ans = 0;
    ans += dist(x[1], y[1], x[2], y[2]);
    ans += dist(x[2], y[2], x[3], y[3]);
    ans += dist(x[3], y[3], x[4], y[4]);
    ans += dist(x[4], y[4], x[1], y[1]);
    cout << fixed << setprecision(15) << ans;
}

K:枝江一梦

题意:给定二维平面,初始在 X 正半轴有 n 点都在 y=0 处。有 m 次操作,每次操作会使得在 x=b 点提高 a×c 然后扩散其周围,但是 c 递减,直到 c=0。问最后正半轴 [1,n] 的 y 轴坐标

思路:先记录一下每个点到左边的最远能到的地方,分别在当前点和左边界标一下,然后分别维护加的数量add_n,减的数量del_n,当前需要加的值add,当前需要减的值del,每次就把后两项分别加上对应的前两项,当到达的点是开始点,也就是初始操作的地方,再维护往后加的数量add_nf,往后减的数量add_nf,当前往后加的值add_f,往后减的值del_f,每次把后两项减去对应的前两项,同时小根堆维护一下每个操作失效的时间即可

void solve(){
    ll n, m;
    cin >> n >> m;
    vector<TLL> v[n + 10];

    for(int i = 1; i <= m; i ++){
        ll a, b, c;
        cin >> a >> b >> c;
        ll l = b - c + 1, r = b + c - 1;
        l = max(1ll, l), r = min(n, r);
        v[l].push_back({a * c, b, 1});
        v[b].push_back({a * c, b, 2});
    }
    
    ll add = 0, del = 0;
    ll add_n = 0, del_n = 0;
    ll add_f = 0, del_f = 0;
    ll add_nf = 0, del_nf = 0;
    priority_queue<PLL, vector<PLL>, greater<PLL>> q;
    for(int i = 1; i <= n; i ++){
        for(auto [x, y, z] : v[i]){
            ll x1 = abs(x);
            if(z == 1){
                if(x < 0){
                    del_n ++;
                    del += x1 - (y - i);
                }
                else{
                    add_n ++;
                    add += x1 - (y - i);
                }
            }
            else{
                q.push({i + x1, x});
                if(x < 0){
                    del_n --;
                    del -= x1;
                    del_nf ++;
                    del_f += x1;
                }
                else{
                    add_n --;
                    add -= x1;
                    add_nf ++;
                    add_f += x1;
                }
            }
        }
        ll res = 0;
        res = add - del + add_f - del_f;
        add += add_n;
        del += del_n;
        while(q.size() && q.top().first <= i){
            if(q.top().second < 0) del_nf --;
            else add_nf --;
            q.pop();
        }
        add_f -= add_nf;
        del_f -= del_nf;
        cout << res << ' ';
    }
}

Pending......

标签:第二十届,int,ll,ACM,add,ans,程序设计,糖果,void
From: https://www.cnblogs.com/RosmontisL/p/18239773

相关文章

  • 《Python程序设计(第二版)》第五章冷门点
    python小白考前复习集合关系运算去掉列表中重复元素,按原列表顺序输出无重复元素的列表集合的存储原理元素必须可哈希查找速度特别快字典函数存储原理字典可以作为if多路分支的替代写法计数作用多项式相加嵌套结构集合一般什么时候用集合呢?就是想要维护一大堆不重......
  • 程序设计基础-C/C++关键字(程序员面试笔试宝典)
    简介生活中的点点滴滴离不开计算机程序,没有程序则没有现代化的生活。coding已不是理工科学生的专属了,任何学科的学生只要掌握一定的编程基础知识,通过系统联系,便可以掌握IT研发工作,成为一名优秀的程序员,本内容详细介绍C/C++当中的关键字。static(静态)变量有什么作用在C语言......
  • B. Mashmokh and ACM
    原题链接题解关键因素:调和级数\(\frac{1}{n}+\frac{1}{n-1}+...+\frac{1}{2}+\frac{1}{1}\)可以近似看成\(log(n)\)code#include<bits/stdc++.h>usingnamespacestd;#definelllonglongconstllmod=1e9+7;lldp[2005][2005];inlinevoidread(ll&x){ x=0......
  • 工程数学上机实验四:共轭梯度法程序设计代码
    function[k,x,val]=frcg(fun,gfun,x0,epsilon,N)%共轭梯度法求解无约束问题%fun,gfun分别为目标函数及其梯度,x0是初始点%epsilon是容许误差,N是最大的迭代次数ifnargin<5,N=10000;endifnargin<4,epsilon=1e-6;endbeta=0.6;sigma=0.4;n=length(x0);k=0;while(k<......
  • 《Python程序设计(第二版)》第一二章冷门点上
    python小白考前复习1.编码(密码本)2.数字类型2.1整数你可以单独使用数字0,但不要前置它幂的优先级高于乘除2.2浮点数科学计数法divmod函数:同时计算商和余数慎用round(x,n)函数abs函数求模关于复数3.字符串类型R方法原始字符串的特点:示例普通字符串与原始字符串的对比原始......
  • PTA--《面向对象程序设计》
    目录 一:超市贴花二:教师类三:快递计价器四:重复数据问题五:List的使用 一:超市贴花某超市有一种促销手段,购买金额超过一定阈值就随机给一个贴花。贴花有不同种类的,种类以编号表示,编号是一个1到100之间的数字。当收集到连续编号的三张贴花时,就可以换一个小礼物。输入样例......
  • 面向对象程序设计课程设计报告——计算器
    报告正文目录概述..............................................................................................................................................................1设计的基本概念和原理.............................................................
  • C程序设计谭浩强例题分析 1.2
    【例1.2】求两个整数之和。【例1.2】求两个整数之和。解题思路:设置3个变量,a和b用来存放两个整数,sum用来存放和数。用赋值运算符“=”把相加的结果传送给sum。这里只列举了一种代码实现如果要看其他代码实现可以到我的:GitHub:三种代码风格我的答案:#include<stdio.h>int......
  • <编译器> 7. 中间代码 | 5. 程序设计
    IR代码中符号代码(label)沿用不变int调用T_Const(inti)Tree模块:1.patchList:真值/假值回填表这里是patchList的生成,至于具体怎么回填后面才会讲structpatchList_{Temp_label*head;patchListtail};//生成stmstm=T_Cjump(T_ge,unEx(......
  • 八(汇编程序设计):输入5个同学成绩(有学号提示),然后排序,最后显示出名次表(学号,成绩)。要求:应
    代码DSEG SEGMENTGRADEDB5DUP(0)XUEHAODB'1','2','3','4','5'BUFDB4DUP(0)INFDB"Student",'$'NEWLINEDB0DH,0AHDSEGENDSSSEGSEGMENTSTACKSKTOPDB50DUP(0)S......