【0521模拟赛】小Z爱数学

题目描述

小Z想求F(n,k),F(n,k)表示n的所有因数pi中,满足n/pi <= k 的和。

小Z发现还是很水,所以他决定加大难度。

小Z还准备了很多个询问。现在你来解决一下吧。

输入输出格式

输入格式:

第一行两个整数m 表示询问的个数

接下来每行两个数ni,ki,表示这个询问的n和k

输出格式:

 ,

也就是把刚好等于k的答案加进去  然后k变大

对于每个询问输出一行一个整数,表示对应的答案。

题目理解:F(n,k)表示n的所有因数qi中,满足n/qi<=k的和,

             m组,每组给定n和k,求       

m<=500000,ni<=100000

解析:k比较大的的答案  包含了k比较小的答案,所以要先把每次询问按k来排序,

         然后我们每次回答询问的时候  如果k不同  就把k变大成现在要问的k,

         也就是把刚好等于k的答案插入线段树, 然后k变大
复杂度 O (nlog^2n+mlogn)
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100000
#define ll long long
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll t[N*3],ans[N*5+10];
int m;
struct que{int n,k,id;}e[N*5+10];
bool cmp(que i,que j){return i.k<j.k;}
ll query(int l,int r){ 
    ll sum=0;
    l+=N-1,r+=N-1;
    sum+=t[l]+t[r]; 
    if(l==r) return sum-=t[l];
    for(;l^r^1;l>>=1,r>>=1){
        if(~l&1) sum+=t[l^1];
        if( r&1) sum+=t[r^1];
    }
    return sum;
}
void Change(int x,int v){
    t[x+=N-1]+=v; 
    while(x) t[x>>=1]=t[x<<1]+t[x<<1|1];
}
void sol(int x){
    for(int i=1;i*x<=N;i++) Change(i*x,i);
}
int main(){
    m=read();
    for(int i=1;i<=m;i++){e[i].n=read();e[i].k=read();e[i].id=i;}
    sort(e+1,e+m+1,cmp);
    int j=0;
    for(int i=1;i<=m;i++){
        while(j<e[i].k) sol(++j);
        ans[e[i].id]=query(1,e[i].n);
    }
    for(int i=1;i<=m;i++) printf("%lld
",ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/PaperCloud/p/6915420.html