2023 (ICPC) Jiangxi Provincial Contest(江西省赛)

怎么说呢,签到题太签到了,后面看似是签到题的也是很考验思维...

L题:Zhang Fei Threading Needles - Thick with Fine

Solution

直接输出n-1

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);

    int n; cin >> n;
    cout << n - 1 << endl;
    return 0;
}

A题:A - Drill Wood to Make Fire

Solution

语法题

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long

signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);

    int t; cin >> t;
    while (t--)
    {
        int n, s, v; cin >> n >> s >> v;
        if (s * v >= n)cout << 1 << endl;
        else cout << 0 << endl;
    }
    return 0;
}

I题:Tree

题意:两种操作,将一棵树两点之间的路径上的所有边权异或上一个数,或者询问一个点周围所有边权的异或和。

Solution

想了很久,最后硬做超时了,考虑这样一个事实:即两点之间的所有点(除了两个端点),必然有有且只有两条边的边权会被异或,而由于两条边a,b都经过了异或操作,所以不影响a异或b的值,

a^c^b^c=a^b^c^c=a^b,所以只需要将两个端点的边权异或和异或c即可,我们直接维护每个点的边权异或和

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 10;

vector<pii>tr[N];
int ans[N];




signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);

    int n, q; cin >> n >> q;
    for (int i = 1; i <= n - 1; i++)
    {
        int a, b, w; cin >> a >> b >> w;
        tr[a].push_back({ b,w });
        tr[b].push_back({ a,w });
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j < tr[i].size(); j++)
            ans[i] ^= tr[i][j].second;
    }
    while (q--)
    {
        int op; cin >> op;
        if (op == 1)
        {
            int x, y, w; cin >> x >> y >> w;
            ans[x] ^= w;
            ans[y] ^= w;
        }
        else
        {
            int x; cin >> x;
            cout << ans[x] << endl;
        }
    }
    return 0;
}

K题:Split

题意:给出一个正整数 n 和一个长度为n的单调不升序列a,然后给出一个正整数 ,表示操作总数。 操作共有两种。第一种是将 a_{x}变成 a_{x-1}+a_{x+1}-a_{x}(1 < x < n)。 第二种是询问操作。假设将序列分为 k段(每段长度至少为 1),每段的价值为最大的数减最小的数,求所有分段方案中最小的 k 段价值和。

Solution

注意到将序列分成K段的操作,也就是在所有数字的间隔中插入(k-1)个隔板,这里假设K==3,即在序列中选择2个地方放入隔板,假设放在a_{x}a_{y}(1\leqslant x<y\leq n-1),由于序列单调不升,所以k段价值和为a_{1}-a_{x}+a_{x+1}-a_{y}+a_{y+1}-a_{n}=a_{1}-a_{n}+a_{x+1}-a_{x}+a_{y+1}-a_{y}

,要使得其最小,即要找到最小的两端差分,查询操作变成了查询前最小k-1段差分之和,这一点我们可以先将差分数组求出来,随后排序+前缀和,但这里还有一个修改操作,这也是让我止步的地方,想了很久没有思路,但这里注意到修改后的值不是凭空产生的的,是与左右两个数有关系的,这里注意到a_{x}被改变后,其前后差分的值只不过交换了位置,不影响差分数组,所以修改操作是无效的,我们只需要关注查询操作即可

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;

int a[N];
int cf[N];
int sum[N];

signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int n; cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        cf[i] = a[i] - a[i - 1];
    }
    sort(cf+1,cf+1+n);
    for(int i=1;i<=n;i++)
    sum[i]=cf[i]+sum[i-1];
    int q; cin >> q;
    while (q--)
    {
        int op, x; cin >> op >> x;
       if(op==1)
        {
          cout<<a[1]-a[n]+sum[x-1]<<endl;
        }
    }
    return 0;
}

J题:Function

题意:给出一个正整数 n (1\leq n\leq 1e5)和 n 个二次项系数为 1 的二次函数,第 i 个函数形如 然后给出一个正整数 m (1\leq m\leq 1e5)),表示操作总数。 操作共有两种,第一种是给出a,b,添加一个二次项系数为 1 的二次函数,形如 y=(x-a)^{2}+b(1\leqslant a,b\leqslant n)。第二种是询问所有二次函数在 x =a(1\leq a\leq n) 处的最小函数值。 具体的,每次操作会先给出操作的类型,如果是 0 表示是第一种操作,如 果是 1 表示是第二种操作。对于第一种操作,会再给出两个正整数 a, b。 对于第二种操作,则会再给出一个正整数 a。

Solution

查询 x = a 时函数的最小值,对于顶点在x==a处的函数,其值为b_{i},由于(1\leq b_{i}\leq n),假设b_{i}取最大值n,则对于x=a左右一定范围的函数,超过一定范围后,其在x=a的值一定大于n,则这些范围的函数可以不用再看,我们取极端情况,其b_{i}=0时,令(x-a)^{2}\geq n,得x\geq a+\sqrt{n}x\leq a-\sqrt{n},我们最多每次枚举2*\sqrt{n}的范围,时间复杂度O(n\sqrt{n})

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;

vector<int>b[N];

signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int n; cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x; cin >> x;
        b[i].push_back(x);
    }
    int q; cin >> q;
    while (q--)
    {
        int op; cin >> op;
        if (op == 0)
        {
            int a, x; cin >> a >> x;
            b[a].push_back(x);
        }
        else
        {
            int a; cin >> a;
            int ans = 1e18;
            int l = max((int)1, a - (int)sqrt(n)-1), r = min(n, a + (int)sqrt(n)+1);
            for (int i = l; i <= r; i++)
            {
                for (int j = 0; j < b[i].size(); j++)
                    ans = min(ans, (a - i) * (a - i) + b[i][j]);
            }
            cout << ans << endl;
        }
    }
    return 0;
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值