首页 > 其他分享 >ABC 杂题

ABC 杂题

时间:2024-11-01 15:09:34浏览次数:1  
标签:le const int long ABC maxn 杂题 dis

ABC186E Throne

有 \(n\) 个圆形排列的椅子,一开始你在 \(s+1\) 上,每次可以向右移动 \(k\) 个位置,求移动到 \(1\) 的最小步数,或报告无解。

\(2\le n,k\le 10^9\)

很容易想到构造方程:

\[s+qk\equiv 0\pmod n \]

\[q\equiv (n-s)k^{-1}\pmod n \]

直接 exgcd 求逆元,算出在 \([1,n-1]\) 范围内的解即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
void exgcd(int a,int b,int &inv,int &x,int &y){
    if(!b) inv=a,x=1,y=0;
    else exgcd(b,a%b,inv,y,x), y-=(a/b)*x;
}
int T;
signed main(){
    cin>>T;
    while(T--){
        int n,s,k,inv,x,y;
        cin>>n>>s>>k;
        int gcd=__gcd(__gcd(n,s),k);
        n/=gcd;s/=gcd;k/=gcd;
        exgcd(k,n,inv,x,y);
        if(inv!=1){
            cout<<-1<<'\n';
        }else{
            inv=(x+n)%n;
            cout<<(n-s)*inv%n<<'\n';
        }
    }
    return 000;
}

ABC186F Rook on Grid

有一个 \(n\times m\) 的网格,其中有 \(k\) 个障碍 \((x_i,y_i)\),有个猴子,它每走一步可以沿着一个方向走任意格,不能穿过障碍,求猴子在两步及以内可以到达的格子数。

\(n,m,k\le 2\times 10^5\)

设 \(X_i\) 为第 \(i\) 列从上到下可以到达的最大坐标,\(Y_i\) 为第 \(i\) 行从左到右可以到达的最大坐标。

先处理出从左往右可以到达的格子数 \(\sum Y_i\),然后考虑从上到下且不重复的格子,若对于 \(j\in[1,X_i],Y_j<i\),则将格子 \((i,j)\) 加入答案,这个限制直接用树状数组二维数点维护即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+34;

int n,m,k;
int x[maxn],y[maxn];
int ans=0;
int tree[maxn];
vector<int>query[maxn];
int lowbit(int x){return x&-x;}
void add(int pos,int c){pos++;for(;pos<=200030;pos+=lowbit(pos)) tree[pos]+=c;}
int q(int pos){pos++;int res=0;for(;pos;pos-=lowbit(pos)) res+=tree[pos];return res;}
signed main(){
    cin>>n>>m>>k;
    // assert(m<=n);
    for(int i=1;i<=max(n,m);i++) x[i]=n+1;
    for(int i=1;i<=max(n,m);i++) y[i]=m+1;
    for(int i=1,X,Y;i<=k;i++){
        cin>>X>>Y;
        x[Y]=min(x[Y],X);
        y[X]=min(y[X],Y);
    }
    
    for(int i=1;i<=x[1]-1;i++) ans+=y[i]-1, query[y[i]].emplace_back(i);
    for(int i=x[1];i<=n;i++) query[1].emplace_back(i);
    for(int i=1;i<y[1];i++){
        for(int j:query[i]) add(j,1);
        ans+=q(x[i]-1);
    }
    cout<<ans;
    return 0;
}

ABC185E Sequence Matching

给一棵树,\(Q\) 次操作:

  • 对于编号为 \(x\) 的边,和其一个端点 \(u\),将 \(u\) 不经过 \(E_x=(u,v)\) 就能到达的点的分数加上 \(k\)。

求操作完后每个点的分数。

\(n\le 2\times 10^5\)

考虑进行标记(差分)。钦定 1 为根,处理出每个点的父亲,则对于每个询问,若 \(u=fa_v\) 则将 \(u\) 子树外的点加上 \(k\),这等价于将全树的分数加上 \(k\) 再将 \(v\) 子树内的点减掉 \(k\);否则,直接将 \(u\) 子树内的点加 \(k\) 即可。

时间复杂度 \(O(n+Q)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+3;

vector<int>e[maxn];

int tag[maxn],f[maxn],n,q;
struct{
    int u,v; 
}E[maxn];
void dfs(int u,int fa){
    f[u]=fa;
    for(int v:e[u]){
        if(v!=fa) dfs(v,u);
    }
}
void dfs1(int u,int fa){
    for(int v:e[u]){
        if(v!=fa){
            tag[v]+=tag[u];
            dfs1(v,u);
        }
    }
}
signed main(){
    cin>>n;
    for(int i=1,u,v;i<n;i++){
        cin>>u>>v;
        E[i]={u,v};
        e[u].emplace_back(v);
        e[v].emplace_back(u);
    }
    dfs(1,0);
    cin>>q;
    while(q--){
        int t,id,x,u,v;
        cin>>t>>id>>x;
        if(t==1){
            u=E[id].u,v=E[id].v;
        }else{
            u=E[id].v,v=E[id].u;
        }
        if(u==f[v]){
            tag[1]+=x;
            tag[v]-=x;
        }else{
            tag[u]+=x;
        }
    }
    dfs1(1,0);
    for(int i=1;i<=n;i++){
        cout<<tag[i]<<'\n';
    }
    return 0;
}

ABC367F Rearrange Query

给你两个序列 \(a,b\),\(q\) 次询问 \(a[l,r],b[L,R]\) 之间每个元素的个数是否相等。

\(a_i,b_i,l,r,L,R\le n\le 2\times 10^5\)

朴素的思路是 \(n^2\) 的,就是考虑开个 \(n^2\) 的桶,对于每个元素进行判断,但是显然爆炸,而且优化不了。

所以只能舍弃正确性,保证复杂度,将每一个数映射到一个随机数(这里将 \(x\) 映射到 \(h^x\))上,由于问题的必要条件是两个的和相等,而因为随机,所有和相等而不满足的概率极小,可以保证正确性。使用乘法,异或来判断也可以。

时间复杂度 \(O(n\log n)\)。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+3;
int a1[maxn],a2[maxn],b1[maxn],b2[maxn];
int l,r,L,R,n,q;
const int mod1=1000000241;
const int mod2=1000000931;
int ha1(int x){
    int ret=1,de=41;
    for(;x;x>>=1,de=de*de%mod1) if(x&1) ret=ret*de%mod1;
    return ret; 
}
int ha2(int x){
    int ret=1,de=37;
    for(;x;x>>=1,de=de*de%mod2) if(x&1) ret=ret*de%mod2;
    return ret; 
}
signed main(){
    cin>>n>>q;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        a1[i]=(a1[i-1]+ha1(x))%mod1;
        // a2[i]=(a2[i-1]+ha2(x))%mod2;
    }
    for(int i=1,x;i<=n;i++){
        cin>>x;
        b1[i]=(b1[i-1]+ha1(x))%mod1;
        // b2[i]=(b2[i-1]+ha2(x))%mod2;
    }
    while(q--){
        cin>>l>>r>>L>>R;
        if(R-L!=r-l){
            cout<<"No\n";
            continue;
        }
        int l1=(a1[r]-a1[l-1]+mod1)%mod1;
        // int r1=(a2[r]-a2[l-1]+mod2)%mod2;
        int l2=(b1[R]-b1[L-1]+mod1)%mod1;
        // int r2=(b2[R]-b2[L-1]+mod2)%mod2;
        if(l1==l2){
            cout<<"Yes\n";
        }else{
            cout<<"No\n";
        }
    }
    return 0;
}
// 单模数都能过

ABC365E Xor Sigma Problem

给你一个序列 \(a\),求其每个子段的异或和的和。

\(n\le 2\times 10^5,a_i\le V\le 10^8\)

由于异或的可加性,求异或和可以用前缀和处理掉,设前缀数组为 \(b\),则题目转化为求 \(\sum\limits_{i=1}^{n}\sum\limits_{j=i+1}^{n} b_{j} \oplus b_{i-1}\)

加法和异或并不具有交换结合律,但是可以发现每次的 \(b_j\) 数量是递减的,而异或是按位运算,所以考虑拆位,每位开一个桶 \(t_x\) 记录二进制第 \(x\) 为为 \(1\) 的个数,对于一个 \(b_i\) 只有 \(b_j\) 在第 \(x\) 位上不同才有贡献,这样计算是 \(O(\log V)\) 的,同样从桶中删除一个 \(b\) 也是 log 的,所以总复杂度为 \(O(n\log V)\)。

最终的式子:

\[ans=\sum\limits_{i=1}^n\sum\limits_{j=1}^{\log_2 b_i+1}2^j f(i,j) \]

\[f(i,j)=\begin{cases}n-i-t_j&b_{i}\And 2^j=1\\t_j&b_{i}\And 2^j=0 \end{cases} \]

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+3;
int a[maxn],b[maxn];
int n;
int ton[64];
bitset<32>bit[maxn];
signed main(){
    cin>>n;
    bit[0]=0;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        a[i]=x;
        b[i]=b[i-1]^x;
        bit[i]=b[i];
        for(int j=0;j<31;j++){
            ton[j]+=bit[i][j];
        } 
    }
    int ans=0;
    for(int i=1;i<n;i++){
        for(int j=0;j<31;j++){
            ton[j]-=bit[i][j];
        }
        for(int j=0;j<31;j++){
            int cnt=bit[i-1][j]?n-i-ton[j]:ton[j];
            ans+=(1ll<<j)*cnt;
        }
    }
    cout<<ans;
    return 0;
}

三倍经验:
P9236 [蓝桥杯 2023 省 A] 异或和之和

P3917 异或序列


ABC371E I Hate Sigma Problems

设 \(f(i,j)\) 为 \([i,j]\) 内不同数字的个数,求 \(\sum\limits_{i=1}^n\sum\limits_{j=i}^n f(i,j)\)。

\(a_i\le n\le 2\times 10^5\)

设 \(g_i\) 为 \(i\) 位置前面第一个与 \(a_i\) 相同的位置,则每个 \(i\) 的贡献区间为 \([l_i,r_i](l_i\in[g_i,i],r_i\in[i,n])\),其贡献为 \((i-g_i)(n-i+1)\),时间复杂度 \(O(n)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+3;
int n,ans;
int a[maxn],f[maxn];
vector<int>v[maxn];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++) v[i].emplace_back(0);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        f[i]=v[a[i]].back();
        v[a[i]].emplace_back(i);
    }
    for(int i=1;i<=n;i++){
        ans=ans+(i-f[i])*(n-i+1);
    }
    cout<<ans;
    return 0;
}

ABC268E Chinese Restaurant (Three Star Version)

给你一个排列 \(p\),求 \(\min\limits_{d=0}^{n-1}\sum\limits_{i=0}^{n-1} dis(i,p_{(i+d)\bmod n})\)。

\(n\le 2\times 10^5\)

考虑到对于一个 \(p_i\),它离 \(i\) 的距离大概如图

img

由两段单调区间构成,分别单增和单减。我们可以统计初始态时上升与下降的个数之差 \(x\),每次 \(d\to d+1\) 时就把初始 \(d=0\) 的和加上 \(x\),再判断是否到达断点(相当于将贡献反向,原来 \(+1\) 的贡献在断点 \(-2\) 后就变为 \(-1\)),再而,\(n\) 为奇数时,\(dis_{\max}\) 有两个点 \(t,t+1\) 取到,所以在这两个点时,先是将 \(+1\to 0\),再在 \(t+1\) 将 \(0\to -1\),开一个桶记录每个 \(d\) 的 \(x\) 的增减即可,时间复杂度 \(O(n)\),代码使用 \(O(n\log n)\) 的写法。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+3;
int n,a[maxn],b[maxn],c[maxn],ad,de,sum,ans=0x3f3f3f3f3f3f3f3f;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
signed main(){
    cin>>n;
    if(n&1){
        for(int i=0;i<n;i++){
            cin>>a[i];
            int dis=min(abs(a[i]-i),n-abs(a[i]-i));
            int dit=min(abs(a[i]-(i+1)),n-abs(a[i]-(i+1)));
            int pos1=a[i],pos2=(a[i]+n/2)%n,pos3=(a[i]+n/2+1)%n,dis1=pos1-i,dis2=pos2-i,dis3=pos3-i;
            if(dis<dit) ad++;
            else if(dis>dit) ad--;
            if(i>pos1) dis1+=n;
            if(i>pos2) dis2+=n;
            if(i>pos3) dis3+=n;
            q.push({dis1,2});
            q.push({dis2,-1});
            q.push({dis3,-1});
            sum+=dis;
        }
    }else{
        for(int i=0;i<n;i++){
            cin>>a[i];
            int dis=min(abs(a[i]-i),n-abs(a[i]-i));
            int dit=min(abs(a[i]-(i+1)),n-abs(a[i]-(i+1)));
            int pos1=a[i],pos2=(a[i]+n/2)%n,dis1=pos1-i,dis2=pos2-i;
            if(dis<dit) ad++;
            else ad--;
            if(i>pos1) dis1+=n;
            if(i>pos2) dis2+=n;
            q.push({dis1,2});
            q.push({dis2,-2});
            sum+=dis;
        }
    }
    while(!q.empty()&&!q.top().first) q.pop();
    ans=sum;
    for(int d=1;d<=n;d++){
        sum+=ad;
        while(!q.empty()&&q.top().first==d){
            ad+=q.top().second;
            q.pop();
        }
        ans=min(ans,sum);
    }
    cout<<ans;
    return 0;
}

ABC374E Sensor Optimization Dilemma 2

唐氏 trick 题。

加工每个产品有 \(n\) 步,每步中可以选择机器 \(S_i\),用 \(p_i\) 费用加工 \(a_i\) 个产品;或者选择机器 \(T_i\),用 \(q_i\) 费用加工 \(b_i\) 个产品,求在总费用不超过 \(x\) 的情况下,求最大可加工的产品数。

\(n,a_i,b_i\le 100,p_i,q_i,x\le 10^7\)

显然可以二分。二分一个 \(t\) 表示产品数,枚举 \(S_i\) 的数量,进而可以算出 \(T_i\) 的数量,时间复杂度 \(O(xn\log xn)\)(AT 少爷机可过),但是考虑到 \(a_i,b_i\) 的范围很小,实际上我们是枚举 \(Cp_i+Dq_i\ge x\),令 \(w=Cp_i+Dq_i-x\),\(w\) 的循环节为 \(\gcd(a_i,b_i)\le 100\),所以我们只要枚举 \(100\) 个 \(C/D\) 即可,时间复杂度 \(O(nT_{w}\log xn)\),槽点是它 \(n\) 怎么开这么小,导致想了一会费用流

标签:le,const,int,long,ABC,maxn,杂题,dis
From: https://www.cnblogs.com/DEV3937/p/18520279

相关文章

  • 杂题选做1
    杂题选做1[ARC112F]DieSiedler注意到如果存在某一个\(j\)满足这种牌的数量大于等于\(2j\),那么一定会兑换为\(j\bmodn+1\)的牌。所以我们考虑这个过程的逆过程,就是将一张牌\(j\)换成\((j-1)!2^{j-1}\)张\(1\)号牌,最终全部的牌都被转化为了\(1\)号牌,但是结果并......
  • 数据结构杂题乱记
    由于是杂题乱记所以题目大多数不会太难。目录P2572[SCOI2010]序列操作题目内容思路代码P2572[SCOI2010]序列操作题目内容给你一个\(01\)序列,支持\(5\)种操作:0lr区间赋值为\(0\);1lr区间赋值为\(1\);2lr区间取反,即\(0\)变\(1\)、\(1\)变\(0\);3lr询......
  • 杂题随笔 10.31 两道LIS相关的题
    https://www.luogu.com.cn/problem/AT_abc354_f题意:给定一个序列a,求出所有的i使得任意一个a的最长子序列包含i。解法:我们先求这个序列的LIS的长度maxx,然后再去正着求一遍最长上升子序列和反着求一遍最长下降子序列即可,如果拼起来等于maxx那么说明i这个点是满足要求的点。注意细......
  • Day65 小贪心 & 自选杂题
    哎怎么必可公益赛被爆破了,怎么lifan还加了几道我们的训练题目作为补偿。CF不知道死了多久了,一上午都没有打成duel!今天上午精神状态明显好了很多,可能和咖啡有点关系吧。按照时间顺序写题吧。AT_arc070_b可以进行撤销背包,也可以算前后缀背包,都是记录方案数。不难的。AT_a......
  • Codeforces Round 981 (Div. 3) ABCDE
    CodeforcesRound981(Div.3)ABCDEA.SakurakoandKosuke藕是看样例直接猜了结论......
  • 强连通分量学习笔记+杂题
    图论系列:前言:僕は明快さ故にアイロニー優柔不断なフォローミー後悔後悔夜の果て相关题单:戳我一.强连通分量相关定义基本摘自oiwiki,相关定义还是需要了解。(实际就是搬了个oiwiki)强连通分量主要在研究有向图可达性,针对的图类型为有向弱联通图。1.强连通定义强连通:对......
  • Educational Codeforces Round 171 (Rated for Div. 2) 10.28 ABCD题解
    EducationalCodeforcesRound171(RatedforDiv.2)10.28(ABCD)题解A.PerpendicularSegments数学(math)计算几何(geometry)题意:给定一个\(X,Y,K\)。需要求解出二维坐标系中的四个点\(A,B,C,D\),满足:\(0\leqA_x,B_x,C_x,D_x\leqX\),\(0\leqA_y,B_y,C_y,D_y\leqY\)。并......
  • Codeforces Round 982 (Div. 2) 10.26 (ABC)题解
    CodeforcesRound982(Div.2)10.26(ABC)题解A.RectangleArrangement数学(math)题意:有一个无限长宽的方形网格,初始为白色,现在有\(n\)个印章,每个印章有自己的宽\(w_i\)和高\(h_i\)。印章会使得网格涂色,变成黑色。这\(n\)个印章都需要使用一次,需要求解出最后网格中黑色......
  • 1.python模块abc抽象类
    1.定义一个抽象基类,不可实例化2.继承抽象基类的类,必须实现抽象基类中@abstractmethod的方法3.继承抽象基类的类,必须实现抽象基类中@abstractmethod的方法4.模拟客户端传参,调用调用子类的中重写功能5.issubclass判断是不是子类6.抽象基类的方法注册7.框架结构8.根据设计图......
  • ABC 377 Review
    ABC377ReviewA模拟题,但是好像wa了一发,有点幽默Code#include<bits/stdc++.h>usingnamespacestd;chars[5];intmain(){ for(registerinti=1;i<=3;++i)s[i]=getchar(); sort(s+1,s+4); if(s[1]=='A'&&s[2]=='B'&&s[3]=='......