首页 > 其他分享 >CSP模拟27

CSP模拟27

时间:2023-08-21 20:11:12浏览次数:34  
标签:27 int Max operatorname dep ch CSP 模拟 dis

A. 道路

考虑修改后的树任意两点间距离与修改前的关系。

例如,\(1\) 和 \(3\) 原本距离为 \(2\),现在距离为 \(1\);\(3\) 和 \(4\) 原本距离为 \(3\),现在距离为 \(2\)。

我们发现,对于原树中两点间的距离 \(\operatorname{dis}\),现在的距离为 \(\lfloor \frac{dis + 1}{2} \rfloor\)。

考虑把这个式子转化一下,变成

\[\left\lfloor \frac{dis + 1}{2} \right\rfloor=\dfrac{\operatorname{dis}+\left[ \operatorname{dis}\equiv1(\!\!\!\!\mod 2 ) \right]}{2} \]

那么我们代入题目给出的式子,得到

\[\sum^{n}_{i=1}\sum^{n}_{j=i+1}(\dfrac{\operatorname{dis}(i,j)+\left[ \operatorname{dis}(i,j)\equiv1(\!\!\!\!\mod 2 ) \right]}{2}) \]

很显然,我们发现,最终答案与边权的奇偶性和原树边权和有关。

考虑如何求路径长度?两点间距离为

\[\operatorname{dis}(i,j)=\operatorname{dep}_i+\operatorname{dep}_j-2\times \operatorname{dep_{\operatorname{lca}(i,j)}} \]

其中后面 \(-2\times \operatorname{dep_{\operatorname{lca}(i,j)}}\) 的部分与路径长度的奇偶性无关,那么直接统计 \(\operatorname{dep}_i\) 和 \(\operatorname{dep}_j\) 奇偶性不同的点对数量就可以求出路径长度为奇数的路径数量。

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 200500;

int n;

struct Edge{
    int next,to;
}e[N << 1];

int h[N],cnt;

void Add(int u,int v) {
    cnt ++;
    e[cnt].next = h[u];
    h[u] = cnt;
    e[cnt].to = v;
}

namespace SOL{
    long long ans = 0;
    int size[N],cnt[N];

    void dfs(int x,int fa,int dep) {
        cnt[dep ^ 1] ++;
        size[x] = 1;

        for(int i = h[x];i;i = e[i].next) {
            int to = e[i].to;

            if(to == fa) 
                continue;
            
            dfs(to,x,dep ^ 1);
            size[x] += size[to];
        }

        ans += 1ll * (n - size[x]) * size[x];
    }
    
    void Work() {
        memset(cnt,0,sizeof(cnt));
        memset(size,0,sizeof(size));

        dfs(1,1,0);

        ans = ans + 1ll * cnt[0] * cnt[1];
        ans /= 2;

        cout << ans << "\n";
        return ;
    }
}

int main() {
    scanf("%d",&n);

    for(int i = 1,u,v;i < n; i++) {
        scanf("%d%d",&u,&v);
        Add(u,v);
        Add(v,u);
    }

    SOL::Work();

    fclose(stdin);
    fclose(stdout);
    return 0;
}

B. 集合

正解好像是 0-1 Trie,不过我们可以乱搞搞过去。

考虑第二个限制,我们可以转化为 \(k \mid x \land k \mid v\),那么 \(x\) 和 \(v\) 都是 \(k\) 的倍数,我们可以预处理加入集合的数 \(u\),把它加入所有它因数的集合里。

这样我们在后面查找 \(v\) 就直接在 \(k\) 的集合中查找就能够保证满足第二个条件。

对于查询操作,我们直接找到小于等于 \(s-x\) 的数,然后在集合中从大到小遍历。

我们知道,两个数异或值最大就是两个数的值相加,如果我们当前记录的最大异或值 Max 已经大于遍历到的 x + v,后面的部分肯定不会再对答案产生贡献了,可以直接退出循环。

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 100500;

int n;
int opt,u,x,k,s;

set<int> S[N];
// S[i] 中的任意数 x 满足 i | x 
// 即存的是 i 的倍数 
// 用于第二个条件 

long long ans,Max;

int main() {
    cin >> n;

    for(int i = 1;i <= n; i++) {
        cin >> opt;
        if(opt == 1) {
            cin >> u;
            for(int i = 1;i <= floor(sqrt(u)); i++) {
                if(u % i == 0) {
                    S[i].insert(u);
                    S[u / i].insert(u);
                }// 记录的是其倍数 
            }
        }
        else {
            cin >> x >> k >> s;
            
            ans = -1;
            Max = -1;

            if(x % k != 0) {
                cout << "-1\n";
                continue;
            }

            set<int>::iterator it = S[k].upper_bound(s - x);
            // 找到大于 x 的最小的数 
            if(it == S[k].begin() || S[k].empty()) {
                cout << "-1\n";
                continue;
            }

            it --;
            // 现在的 it 指向的是满足第一个条件和第二个条件的最大的数

            while(it != S[k].begin()) {
                int v = *it;

                if(Max > x + v) 
                    break;
                // 异或最大值就是 x + v 
                // Max 已经超过 x + v 肯定不能更新答案 
                
                if(Max < (v ^ x)) {
                    Max = v ^ x;
                    ans = v;
                }

                it --;
            }

            if((*it ^ x) > Max)
                ans = *it;
            
            cout << ans << "\n";
        }
    }
    return 0;
}

C. 科目五

模拟赛 T3,考场思路是直接二分,对每辆车进行二分,答案取每辆车答案的最大值,时间复杂度 \(\operatorname{O}(nm \log n)\)。

这样显然会 TLE,我们考虑优化。

  1. 考虑判一下记录的答案能否支持当前这辆车走完全程,如果可以,那就不用二分这辆车了,因为它的答案一定比原先的答案小,计算出来也不会更新答案。
  2. 对于第一条情况,我们把每辆车的顺序打乱重排能获得更优的期望复杂度。

跑的飞快,直接薄纱正解。

#include <bits/stdc++.h>

using namespace std;

const int N = 550;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while( ch < '0' || ch > '9' ) {if( ch == '-' ) f=-1;ch=getchar();}
    while( ch >= '0' && ch <= '9' ) {x=x*10+(ch-48);ch=getchar();}
    return x*f;
}

int n,m;

long long pos[N];

struct Trip{
    int s,t;
    long long c,r;
}a[250500];

int Max[N][N];

int i;

bool Check(long long &V) {
    long long dis,need,times = 0,remain = V;

    if(Max[a[i].s][a[i].t] * a[i].c > V)
        return 0;

    for(int j = a[i].s;j < a[i].t; j++) {
        dis = pos[j + 1] - pos[j];
        need = dis * a[i].c;

        if(need <= remain) 
            remain -= need;
        else {
            times ++;
            remain = V - need;
        }
    }

    if(times > a[i].r)
        return 0;
    

    return 1;
}

int main() {
#ifdef ONLINE_JUDGE == 1
    freopen("drive.in","r",stdin);
    freopen("drive.out","w",stdout);
#endif
    n = read();
    m = read();

    for(int i = 1;i <= n; i++) 
        pos[i] = read();

    for(int i = 1;i <= m; i++) {
        a[i].s = read();
        a[i].t = read();
        a[i].c = read();
        a[i].r = read();
    }

    for(int i = 1;i <= n; i++){
        long long maxn = 0;
        for(int j = i + 1;j <= n; j++) {
            maxn = max(maxn,pos[j] - pos[j - 1]);
            Max[i][j] = maxn;
        }
    }

    random_shuffle(a + 1,a + m + 1);

    long long ans = 0;

    for(i = 1;i <= m; i++) {
        if(Check(ans))
            continue;

        long long l = max(Max[a[i].s][a[i].t] * a[i].c,ans + 1);
        long long r = (pos[a[i].t] - pos[a[i].s]) * a[i].c;
        long long mid,res = r;

        while(l <= r) {
            mid = (l + r) >> 1;

            if(Check(mid)) {
                r = mid - 1;
                res = mid;
            }
            else 
                l = mid + 1;
        }

        ans = max(ans,res);
    }
    
    cout << ans << "\n";
    fclose(stdin);
    fclose(stdout);
    return 0;
}

D. 监狱

咕了。

标签:27,int,Max,operatorname,dep,ch,CSP,模拟,dis
From: https://www.cnblogs.com/baijian0212/p/csp-27.html

相关文章

  • CSP模拟27
    考的有一点意外,出乎意料。[CF1060E]SergeyandSubway题目链接考场上打假了,乐。设\(dis_{i,j}\)表示\(i\)和\(j\)的树上距离。很容易发现,答案其实就是:\[\sum\lceil\frac{dis_{i,j}}{2}\rceil\]其实就是所有点对的距离,加上距离为奇数的点对的个数,最后除以二就可......
  • 8.21 模拟赛小记
    A.吃饭路上也要锻炼,原P3505[POI2010]TEL-Teleportation咱现在思路通了,代码实现可能得鸽一鸽。两个强强的博客:https://www.cnblogs.com/stoorz/p/12182770.html,https://www.cnblogs.com/reywmp/p/14014611.html。是很难的思维题,涉及乘法原理和图论,用到了分层思想。统计答案时......
  • BGP协议---基于RFC4271标准
    [email protected],2023DescriptionBGP协议---基于RFC4271标准。RFC4271是最新的BGPv4版本的协议。虽然直接看协议是非常晦涩难懂的,而且104页的全英文,真的很难完全阅读下来,但如果理解有出入,还是看RFC最为标准了。第1、2、3章自己就可......
  • 【考后总结】8 月 CSP 模拟赛 8
    8.21CSP模拟27晴天-周杰伦故事的小黄花从出生那年就飘着童年的荡秋千随记忆一直晃到现在ReSoSoSiDoSiLaSoLaSiSiSiSiLaSiLaSo吹着前奏望着天空我想起花瓣试着掉落为你翘课的那一天花落的那一天教室的那一间我怎么看不见消失的下雨天我好想......
  • 北大ACM poj1002 487-3279
    487-3279TimeLimit:2000MS MemoryLimit:65536KTotalSubmissions:191845 Accepted:33280DescriptionBusinessesliketohavememorabletelephonenumbers.Onewaytomakeatelephonenumbermemorableistohaveitspellamemorablewordorphrase.......
  • 2023.8.21 模拟赛
    A多次询问\(l,r\),求\(\sum_{x=l}^r\sum_{y=x}^ra_x\otimes\gcd(a_x\sima_y)\),其中$\otimes$是异或。我们先拆解询问,\(Ans=\sum_{x=1}^r\sum_{y=x}^ra_x\otimes\gcd(a_x\sima_y)-\sum_{x=1}^{l-1}\sum_{y=x}^ra_x\otimes\gcd(a_x\sima_y)\)然后离线处理一下......
  • 模拟SSH爆破攻击
    第一步开启靶机的SSH服务开启步骤:打开终端并以root用户身份登录(第二步kali自带SSH服务器的可省略)使用以下命令安装SSH服务器apt-getupdateapt-getinstallopenssh-server安装完成后。SSH服务将自动启动。可使用以下命令检查SSH服务的状态servicesshstatus......
  • 使用JMeter模拟设备通过MQTT发送数据
    需求:需要一个工具能够支持MQTT协议发送各种不同的数据。目的:模拟小型温室设备反馈,搭建一个测试环境,根据测试的数据显示硬件的状态和数值。工具:JMeter环境:需要配置Java运行环境。操作步骤:1.下载JMeter运行包下载地址:https://jmeter.apache.org/download_jmeter.cgi,下载后可以解压......
  • 【刷题笔记】27. Remove Element
    题目Givenanarraynumsandavalueval,removeallinstancesofthatvaluein-placeandreturnthenewlength.Donotallocateextraspaceforanotherarray,youmustdothisbymodifyingtheinputarrayin-placewithO(1)extramemory.Theorderofeleme......
  • CSP-J2022 复盘
    T1乘方方法\(1\):使用快速幂,判断答案是否\(\geq10^9\)。方法\(2\):特判\(1\)的情况,其余的可以直接乘。此处给出方法\(2\)的代码。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;lla,b;intmain(){ cin>>a>>b; if(a==1)cout<<1; else{ ......