ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ABC-255

2022-06-20 13:01:31  阅读:214  来源: 互联网

标签:ABC int ll seg le fi mod 255


E - Lucky Numbers

Problem

给定长度为\(N-1\)的序列\(S\),长度为\(N\)的序列\(A\)定义为\(A_i+A_{i+1}=S_i\),现在有\(M\)个幸运数字\(X_i\),问怎样的序列\(A\)可以使得序列\(A\)中包含的幸运数字最多,输出这个最多的个数。

\(1\le N\le 2\times 10^5\),\(1\le M\le 10\)

Solve

把\(A_i\)展开,发现\(A_i=S_i'+(-1)^iA_1\),那么假设\(A_i\)是一个幸运数字,那么\((-1)^iA_1=A_i-S_i'\)

确定\(A_1\)取哪个值的时候,会产生最多的幸运数,不需要枚举\(A_i\),也没办法枚举,但可以通过幸运数取计算\(A_1\)的值,然后统计可以由幸运数字得到的最多的\(A_1\),最多的\(A_1\)的个数就是答案。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n,m;
    cin>>n>>m;
    vector<ll>s(n+1),x(m+1);
    for(int i=1;i<n;i++) cin>>s[i];
    for(int i=1;i<=m;i++) cin>>x[i];

    map<ll,ll>cnt;
    auto cal=[&](ll pre,int xs)->void{
        if(xs==1){
            for(int i=1;i<=m;i++) cnt[x[i]-pre]++;
        }else{
            for(int i=1;i<=m;i++) cnt[pre-x[i]]++;
        }
    } ;
    ll pre=0;
    cal(0,1);
    for(int i=1,xs=1;i<n;i++)
    {
        xs=-xs;
        pre=s[i]-pre;
        cal(pre,xs);
    }
    ll ans=0;
    for(auto [p,c]:cnt){
        ans=max(ans,c);
    }
    cout<<ans<<'\n';
}

F - Pre-order and In-order

Problem

给定二叉树的前序遍历和中序遍历,求二叉树的形态

Solve

分治做法,按照前序遍历的顺序,当前前序遍历的值就是当前递归子树的根\(rt\),在中序遍历中找到当前的根的位置记为\(p\),那么这棵子树的左右儿子坑定在\(p\)的左右连边,记录一下边界即可。

Code

#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin>>n;
    vector<int>pre(n+1);
    vector<int>mid(n+1);
    vector<int>pos(n+1);
    for(int i=1;i<=n;i++) cin>>pre[i];
    for(int i=1;i<=n;i++) cin>>mid[i],pos[mid[i]]=i;

    vector<int>L(n+1),R(n+1);
    if(pre[1]!=1){
        puts("-1");
        return 0;
    }
    //S,T为中序遍历的边界,s,t为前序遍历的边界
    auto dfs=[&](auto self,int s,int t,int S,int T)->bool{
        int r=pre[s],p=pos[r];
        if(p<S||T<p) return false;
        if(p-S>0){  //p-S即为左子树大小
            L[r]=pre[s+1];
            if(!self(self,s+1,s+p-S,S,p-1)) return false;
        } 
        if(T-p>0){//T-p即为右子树大小
            R[r]=pre[s+p-S+1];
            if(!self(self,s+p-S+1,t,p+1,T)) return false;
        }
        return true;
    };
    if(!dfs(dfs,1,n,1,n)){
        cout<<-1<<'\n';
        return 0;
    }

    for(int i=1;i<=n;i++) cout<<L[i]<<" "<<R[i]<<'\n';
        return 0;
}

G - Constrained Nim (博弈论、优化)

Problem

Solve

Code

Ex - Range Harvest Query(珂朵莉树)

Problem

有\(N\)棵果树,编号从\(1\)到\(N\),第\(i\)个果树每天会长出\(i\)个果子。现在有\(Q\)次操作,每次操作给出三个整数\(L_i,R_i,D_i\),保证\(D_i\)严格递增,表示第\(D_i\)天会在区间\(L_i,R_i\)把果树上的水果全部摘完,每次你需要回答出摘了多少个果子。

\(1\le N\le 10^{18}\),\(1\le Q\le 2\times 10^5\),$1\le D_1\lt D_2\lt \cdot\cdot\cdot\lt D_Q\le 10^{18} $

Solve

每个区间记录上一次被采摘的时间\(pt\),然后如果遇到最新的采摘时间\(nt\),那么这个区间的贡献就是\(\frac{(r+1)(r-l+1)}{2}(nt-pt),每次合并过程中删除线段的时候统计贡献即可\)。

Code

#include <bits/stdc++.h>
#define fi first
#define se second
#define ll long long
using namespace std;
const int mod=998244353;
struct ODT{
   map<pair<ll,ll>,ll>seg;//左闭右开的区间
   ll L,R;
   ODT(ll L_,ll R_){
      seg[{L_-1,L_-1}]=-1;
      seg[{R_+1,R_+1}]=-1;
      seg[{L_,R_}]=0;
      L=L_-1,R=R_+1;
   }
   //delseg、addseg写自己在删除或添加线段是要统计的信息,自己传入函数
   void assign(ll l,ll r,ll v,function<void(ll,ll,ll)>delseg=[](ll l,ll r,ll v){},
               function<void(ll,ll,ll)>addseg=[](ll l,ll r,ll v){}){
        auto split=[&](ll x){
            auto p=prev(seg.lower_bound({x,L}));
            if(p->fi.se>x){
              ll l=p->fi.fi,r=p->fi.se,v=p->se;
              seg.erase(p);
              seg[{l,x}]=v;
              seg[{x,r}]=v;
            }
        };
        split(l),split(r);//分开两头的区间
        auto pl=seg.lower_bound({l,L});
        //合并中间的区间
        while(1){
          auto pr=pl;
          pr++;
          if(pl->fi.fi>=r) break;
          delseg(pl->fi.fi,pl->fi.se,pl->se);
          seg.erase(pl);
          pl=pr;
        }
        addseg(l,r,v);
        seg[{l,r}]=v;
   }
};

ll ans;
int main()
{
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  ll n;
  int q;
  cin>>n>>q;
  ODT t(1,n+1);
  while(q--)
  {
     ll d,l,r;
     cin>>d>>l>>r;
     ans=0;
     ++r;
     t.assign(l,r,d,
            [&](ll l,ll r,ll v){
             l%=mod,r%=mod;
             ans=(ans+1LL*(l+r-1)*(r-l)/2%mod*((d-v+mod)%mod)%mod)%mod;
           },
           [&](ll l,ll r,ll v){} );
     if(ans<0) ans=ans+mod;
     cout<<ans<<'\n';
  }
}

标签:ABC,int,ll,seg,le,fi,mod,255
来源: https://www.cnblogs.com/Arashimu0x7f/p/16392878.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有