跳转至

25/10/03

T1

给你一个数 \(n\),你想知道对于 \(m(1≤m≤n)\),有多少个满足 \(\frac{n}{m}\) 是整数或者可以被表示成 \(a+\frac{1}{b}(a≥1,b≥2,a,b∈N)\) 的形式。

由于这个问题太简单了,请对 \([L,R]\) 之间的所有整数回答。由于答案很大,记 \(f(n)\) 表示 \(n\) 的答案,输出 \(\sum_{n=L}^R(f(n)⊕n)\) 的结果。

Solution

\(\frac{n}{m}=a+\frac{1}{b}=\frac{ab+1}{b}\),设 \(n=(ab+1)c\)

整数的情况可以视为 \(b=1\) 的情况,还要加上 \(n=m\) 的情况。

我们考虑类似根号分治的东西,令 \(T=R^{\frac{1}{3}}\)

  1. 对于 \(c\le T\) 的,枚举 \(c\)\(a,b\) 中最小的那一个,复杂度 \(O(R^{\frac{2}{3}})\)
  2. 对于 \(c>T\) 的,我们选择枚举 \(ab(<\frac{R}{T})\),复杂度 \(O(R^{\frac{2}{3}})\)

因为还要枚举另一项更新答案,复杂度还要加上 \(O(\sum_{n=L}^Rf(n))\)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+5,V=7e7+5;
ll L,R,T,ans[N],res;
ll pr[V],f[V],tot;
bool vis[V];
void Init() {
    f[1]=1;
    int mx=R/(T+1);
    for(int i=2;i<=mx;i++) {
        if(!vis[i]) {
            pr[++tot]=i;
            f[i]=2;
        }
        for(int j=1;j<=tot&&i*pr[j]<=mx;j++) {
            vis[i*pr[j]]=1;
            if(!(i%pr[j])) {
                f[i*pr[j]]=f[i]*f[pr[j]]-f[i/pr[j]];
                break;
            }
            f[i*pr[j]]=f[i]*f[pr[j]];
        }
    }
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>L>>R;
    T=min(R,(ll)pow(R,0.33));
    for(ll c=1;c<=T;c++) {
        for(ll a=1;(a*a+1)*c<=R;a++) {
            for(ll b=max(a,(L-c+a*c-1)/(a*c));(a*b+1)*c<=R;b++) {
                ++ans[(a*b+1)*c-L];
                if(a!=b) ++ans[(a*b+1)*c-L];
            }
        }
    }
    /*预处理 $1\sim n/T$ 的约数个数或直接枚举
    for(ll a=1;(a*a+1)*(T+1)<=R;a++) {
        for(ll b=a;(a*b+1)*(T+1)<=R;b++) {
            for(ll c=max((L+a*b)/(a*b+1),T+1);(a*b+1)*c<=R;c++) {
                ++ans[(a*b+1)*c-L];
                if(a!=b) ++ans[(a*b+1)*c-L];
            }
        }
    }*/
    Init();
    for(ll ab=1;(ab+1)*(T+1)<=R;ab++) {
        for(ll c=max((L+ab)/(ab+1),T+1);(ab+1)*c<=R;c++) {
            ans[(ab+1)*c-L]+=f[ab];
        }
    }
    for(ll i=L;i<=R;i++) res+=i^(ans[i-L]+1);
    cout<<res;
    return 0;
}

T2 P9292 [ROI 2018] Robomarathon

Subtask 1

对于每个人直接在它的位置上放喇叭就行。

答案即为左边 \(a_j-j<a_i-i\)\(j\) 个数,加上右边 \(a_j+j<a_i+i\)\(j\) 个数。

Subtask 2

对于 \(i\) 的答案,我们如果在一个位置放喇叭,距离 \(i\) 大于等于这个位置的也会贪心地放上喇叭。

假设 \(i\le\frac{n}{2}\),发现在第一个位置与第一个位置关于 \(i\) 对称的及后面的位置都放上喇叭(情况一),或者只在最后一个位置放上喇叭(情况二),会让选手发挥最差。

\(i>\frac{n}{2}\) 同理。

下面计算情况一,令 \(len=\min(i-1,n-i)\),分类讨论每个 \(j\) 的贡献:

  1. \(i-len\le j <i\),贡献为 \([a_j+j<a_i+i]\)
  2. \(i<j\le i+len\),贡献为 \([a_j-j<a_i-i]\)
  3. \(j<i-len\),贡献为 \([a_j<a_i+len]\)
  4. \(j>i+len\),贡献为 \([a_j<a_i+len]\)

就是一个简单二维数点。

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
const int N=4e5+5;
int n,typ,a[N],qt;
int ans[N];
struct BIT {
    int S[N];
    void Update(int x,int v) {
        for(;x<=n;x+=x&-x) S[x]+=v;
    }
    int Query(int x) {
        int res=0;
        for(;x;x-=x&-x) res+=S[x];
        return res;
    }
    int Query(int x,int y) {
        return Query(y)-Query(x-1);
    }
}B1;
struct QRY {
    int l,r,v,id;
}Q[N*3];
vector<pair<int,int> > qry1[N],qry2[N],qry3[N];
void Add(int l,int r,int v,int id) {
    Q[++qt]={l,r,v,id};
}
void Calc1() {
    for(int i=1;i<=n;i++) B1.S[i]=0;
    sort(Q+1,Q+qt+1,[](const QRY &x,const QRY &y) {
        return x.v==y.v?x.id<y.id:x.v<y.v;
    });
    for(int i=1;i<=qt;i++)
        if(Q[i].id) ans[Q[i].id]+=B1.Query(Q[i].l,Q[i].r);
        else B1.Update(Q[i].l,1);
}
void Calc2() {
    sort(Q+1,Q+n+1,[](const QRY &x,const QRY &y) {
        return x.v<y.v;
    });
    for(int l=1,r=1;l<=n;l=r+1,++r) {
        while(r<n&&Q[l].v==Q[r+1].v) ++r;
        for(int i=l;i<=r;i++) ans[Q[i].id]=max(ans[Q[i].id],l-1);
    }
}
void Solve1() {
    for(int i=1;i<=n;i++) {
        Add(1,i-1,a[i]-i-1,i);
        Add(i,i,a[i]-i,0);
    }
    Calc1();
    qt=0;
    for(int i=1;i<=n;i++) {
        Add(i+1,n,a[i]+i-1,i);
        Add(i,i,a[i]+i,0);
    }
    Calc1();
}
void Solve2() {
    for(int i=1;i<=n;i++) {
        int len=min(i-1,n-i),pl=i-len,pr=i+len;
        Add(1,pl-1,(a[i]+n-i)-1,i);
        Add(pr+1,n,(a[i]+i-1)-1,i);
        Add(i,i,a[i],0);
    }
    Calc1();
    qt=0;
    for(int i=1;i<=n;i++) {
        int len=min(i-1,n-i),pl=i-len,pr=i+len;
        Add(pl,i-1,(a[i]+i)-1,i);
        Add(i,i,a[i]+i,0);
    }
    Calc1();
    qt=0;
    for(int i=1;i<=n;i++) {
        int len=min(i-1,n-i),pl=i-len,pr=i+len;
        Add(i+1,pr,(a[i]-i)-1,i);
        Add(i,i,a[i]-i,0);
    }
    Calc1();
    for(int i=1;i<=n;i++) Q[i]={0,0,a[i]-i,i};
    Calc2();
    for(int i=1;i<=n;i++) Q[i]={0,0,a[i]+i,i};
    Calc2();
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>typ;
    for(int i=1;i<=n;i++) cin>>a[i];
    if(typ==1) Solve1();
    else Solve2();
    for(int i=1;i<=n;i++) cout<<ans[i]+1<<"\n";
    return 0; 
}

T3