其他分享
首页 > 其他分享> > ABC-255

ABC-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