Codeforces Round #813 (Div. 2)A-E2

Codeforces Round #813 (Div. 2)

过程

本场A,B快速签到,但C卡了一下,D做法一开始直接把小的变大,然后发现假了,把自己hack了,随后想到了三分寻找最合适的变连续的一串从小到大的数字,但还是假了,只能赛后补提了。
传送门

题目

A

统计前k个数里面有多少个大于k即可

void Solve(){
 cin>>n>>m;
 vector<int>a(n+1);
 rep(i,1,n) cin>>a[i];
 int ans=0;
 rep(i,1,m) if(a[i]>m) ans++;
 cout<<ans<<endl;
}  

B

因为n与n-1互素,所以lcm(n,n-1)=n(n-1),而lcm(a,b)<=ab,故此时lcm为最大值,因此从大到小搭配即可。

void Solve(){
 cin>>n;vector<int>a(n+1);
 rep(i,1,n) a[i]=i;
 for(int i=n;i>1;i-=2) swap(a[i],a[i-1]);
 rep(i,1,n) cout<<a[i]<<" ";
 pts;
}  

C

如果出现\(a_i>a_{i+1}\),n那么此时\(a_i\)之前的所有元素都要变为0,那么记录一个\(b_{a[i]}\)表示\(a_i\)这个值是否已经变为0,维护一个单调栈,变为0的次数即为答案

int n;
void Solve(){
 cin>>n;vector<int>a(n+1),b(n+1);
 rep(i,1,n) cin>>a[i],b[a[i]]=a[i];
 vector<P>c;int ans=0;
 rep(i,1,n){
  if(!c.size()) c.pb(P(b[a[i]],a[i]));
  else if(c.back().first<=b[a[i]]) c.pb(P(b[a[i]],a[i]));
  else if(c.back().first>b[a[i]]) {
   for(auto x:c) {
    if(b[x.second]) ans++;
    b[x.second]=0;
   }
   c.clear();c.pb(P(b[a[i]],a[i]));
  }
 }
 cout<<ans<<endl;
}  

D

因为是完全图,所以\(u-v\)只需要经过两次最小的\(a_i\)即可到达,这是其中一个限制。其次对于\(\max_{1\leq u<v\leq n}d(u,v)\),因为区间最小值是单调递减的,因此上式等价于\(\max_{1\leq i\leq n-1} min(a_i,a_{i+1})\).

那么我们可以二分这个最大距离\(x\),对于\(2*a_i<x\)\(a_i\),将其修改为为\(1e9\),否则最大距离\(x\)不可行。
之后看\(\max_{1\leq i\leq n-1} min(a_i,a_{i+1})\)是否大于\(x\),如果大于则当前\(x\)可行,如果不大于,如果只剩一次修改机会,那就需要判断是否存在一个\(a_i\geq x\),如果存在,将其左右的数修改即可满足条件,否则无法满足条件,对于剩两次以上修改机会,则已经满足条件,满足二分性。

至此,二分范围为\(1-1e9\),可解决问题。

int n,k;
bool check(int x,vector<int>c){
 int num=k;
 rep(i,1,n){
  if(c[i]*2<x) num--,c[i]=1e9;
 }
 if(num<0) return 0;
 int maxx=-1;
 rep(i,1,n-1) maxx=max(maxx,min(c[i],c[i+1]));
 if(maxx>=x) return 1;
 if(num==0) return 0;
 if(num>1) return 1;
 rep(i,1,n){
  if(c[i]>=x) return 1;
 }
 return 0;
}
void Solve(){
 cin>>n>>k;
 vector<int>a(n+1),c;vector<P>b(n+1);
 rep(i,1,n) cin>>a[i];
 int l=1,r=1e9,ans=r;
 while(l<=r){
  c=a;
  int mid=(l+r)>>1;
  if(check(mid,c)) ans=mid,l=mid+1;
  else r=mid-1;
 }
 cout<<ans<<endl;
}  

E

分析题意并打表,可以发现一个坏的三元组\((i,j,k),l\leq i<j<k\leq r\)需满足的条件是\(lcm(i,j,k)=k\)\(lcm(i,j,k)=2*k且i+j+k>2*k\),当\(lcm(i,j,k)=3*k的时候i+j+k一定小于3*k\)

首先三元组总数为\(\frac{(r-l+1)(r-l)(r-l-1)}{6}\)

对于\(lcm(i,j,k)=k\)的部分,我们可以发现\(i,j\)一定是\(k\)\(k\)以外的所有因子,所以求出在\([l,k]\)范围内k除自身以外的因子个数,其两两组合的方案数为\(C(n,2)\),在\([l,r]\)内依次遍历减去即可。

对于\(lcm(i,j,k)=2*k\)的部分,要使\((i+j>k)\)\(i,j\)\(2*k\)的因数,即\(i=\frac{2k}{x},j=\frac{2k}{y},x!=y,x,y>2\),此时只有\(\frac{2k}{3}+\frac{2k}{4},\frac{2k}{3}+\frac{2k}{5}\)这两种组合满足条件,即此时\(2*k为12或30的倍数时,这种情况才会出现\)

对于E1,数据量较少,直接暴力处理即可。

int l,r;
bool fit(int x){return (x<=r)&&(x>=l);}
void solve(){
    l=read(),r=read();
    vector<int>cnt(r+1);
    rep(i,l,r){
        for(int j=2*i;j<=r;j+=i) cnt[j]++;
    }
    ll len=(r-l+1);
    ll ans=len*(len-1)*(len-2)/6;
    rep(i,l,r) ans-=1LL*cnt[i]*(cnt[i]-1)/2;
    for(int i=12;i<=2*r;i+=12){
        if(fit(i/2) && fit(i/3) && fit(i/4)) ans--;
    }
    for(int i=30;i<=2*r;i+=30){
        if(fit(i/2) && fit(i/3) && fit(i/5)) ans--;
    }
    print(ans);pts;
}  

对于E2,我们要想办法加速求出这两种情况。

首先对于\(lcm(i,j,k)=2*k\)的部分,即以\([l,r]\)内所有的数做\(k\):
\(2*k\)为12的倍数,\(k\)为6的倍数,故k有\(\frac{r}{6}\)种可能,但有部分组合种\(i\)可能小于\(l\),故要减去\(\frac{l-1}{3}\),故总共有\(max(\frac{r}{6}-\frac{l-1}{3},0)\)种组合。

\(2*k\)为30的倍数时,同上,共有\(max(\frac{r}{30}-\frac{l-1}{6},0)\)种组合。

对于\(lcm(i,j,k)=k\)的部分,在E1中我们可以维护出\([l,r]\)范围内每个数x在\([l,x-1]\)范围内的因子个数,然后两两组合,相当于用大的因子与所有小的因子匹配,在E2中,我们可以离线出来每个询问的区间\([l,r]\),对于相同的右端点\(r\),我们维护小于\(r\)的所有的数作为因子所能产生的贡献,每个数的的贡献即曾经所有小于它的因子个数的和。

具体来说,我们遍历\([1,2e5]\)种每一个数\(i\),枚举\(i\)的因子,对于\(i\)的第\(j\)大的因子,假设\(i\)\(m\)个因子,因为我们将\(r\)固定,\(l\)未知,故我们记录该因子对后续因子的贡献,即该因子后续到\(r\)可以有\(m-j-1\)种组合法,计算时对于每个固定的\(r\),可以用前缀和相减即可得出该种方法数。

int R;
struct BIT{
 ll t[maxn];
 inline int low(int x){return x&(-x);}
 void update(int x,int val){
  for(int i=x;i<=R;i+=low(i)) t[i]+=val;
 }
 ll sum(int x){
  ll s=0;
  for(int i=x;i;i-=low(i)) s+=t[i];
  return s;
 }
}T;

void solve(){
    int t=read();R=-1;
    vector<P>q(t+1);
    rep(i,1,t){
        int l=read(),r=read();
        q[i]={l,r};
        R=max(r,R);
    }
    vector<vector<P>>Q(R+1);
    vector<vector<int>>yz(R+1);
    vector<ll>res(t+1);
    rep(i,1,t) Q[q[i].second].pb({q[i].first,i});
    rep(i,1,R){
        for(int j=2*i;j<=R;j+=i) yz[j].pb(i);
    }
    rep(i,1,R){
        for(int j=0,m=yz[i].size();j<m;++j){
            T.update(yz[i][j],m-j-1);
        }
        for(auto x:Q[i]) res[x.second]=T.sum(i)-T.sum(x.first-1);
    }
    rep(i,1,t){
        int l,r;l=q[i].first,r=q[i].second;
        int len=r-l+1;
        ll ans=1LL*len*(len-1)*(len-2)/6;
        ans-=res[i];
        //12k  6k 4k 3k
        int t1=r/6,t2=(l-1)/3;
        if(t1>t2) ans-=t1-t2;
        //30k  15k 10k 6k
        t1=r/15,t2=(l-1)/6;
        if(t1>t2) ans-=t1-t2;
        print(ans);pts;
    }
}  
posted @ 2022-08-15 00:22  Mr_cold  阅读(51)  评论(0)    收藏  举报