校内集训20180925

T1(Loj6083):

给定L,R,求在[L,R]区间的数的所有因子的最高位数码出现的次数。比如A=17*23,A对1的贡献和对2的贡献均为1。L<=R<=10^9。

题解:

直接枚举L,R算因数显然不可行,既然是每个因子对应几个贡献,我们可以考虑枚举每个因子计算答案。

由于1-9是分开计数的,那么可以将所有最高位分别为1-9的因子归到一起计算。

按数位dp的思想,分别计算[1,R]和[1,L-1]内最高位为i的满足条件的因子个数,相减即可。

易知首位为i的k位数取值范围为[i*10^k,(i+1)*10^k-1),记作[l,r]。

朴素算法是从l开始枚举每个数i,设当前上界为n,i对答案的贡献是n/i(i分之n下取整)。

(显然当i作为i,2i,3i,……,(n/i)*i的约数时有贡献,(n/i)+1)*i超出上界)

那么理论复杂度还是O(10^9)的,但考场上写这个居然有70pts……

(不过10组全是极限数据出题人可能会被D……)

重要的是,我们发现如果k较大时,有很多数的贡献其实是一样的,也就是n/x==n/y。

那么如果将贡献值相同的数一并计算,就能将O(n)的复杂度降成O(n/min(i)),堪称奇迹。

对于某一个i,满足n/j==n/i的最大的j显然是n/(n/i)。[可以由下取整的特点:n/k是整数中最后一个乘上k不超过n的数得知]

那么答案累加(j-i+1)*(n/i)即可。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 100005
#define MAXM 500005
#define INF 0x7fffffff
#define mod 1000000007
#define ll long long

inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

inline ll calc(ll num,ll l,ll r){
    ll ans=0,x=l,y=0;
    while(x<=r){
        y=min(r,num/(num/x));
        ans+=(y-x+1)*(num/x);
        x=y+1;
    }    
    return ans;
}

inline ll solve(ll num,ll x){
    ll y=1,ans=0;
    while(x<=num){
        ans+=calc(num,x,min(x+y-1,num));
        x*=10,y*=10;
    }
    return ans;
}

int main(){
    ll L=read(),R=read();
    for(ll i=1;i<=9;i++)
        printf("%lld
",solve(R,i)-solve(L-1,i));
    return 0;
}

T2(Loj2043):

已知平面下的N个点坐标,求欧氏距离下的k远点对。

 

题解:

据说是kd-tree,不会……

T3(Loj6159):

给定一棵N个点的树,每个点有点权A[i],求最长的gcd不等于1的链。N<=10^5,A[i]<=10^9。

题解:

考虑暴力枚举各个点的所有质因数后dfs,每遍历一个质因数后不再遍历它,

显然每个点被遍历的次数等于它的质因数个数也就是logA[i],复杂度O(NlogA[i])。

然后我就T了。原因是我把素数表打的太大。

设A[i]=p1^a1*p2^a2*……*pn^an。显然不会出现两个>=sqrt(10^9)的p[i],

所以素数表打到sqrt(10^9),分解完质因数如果x还不等于1则剩余的那个数就当一个大素数处理一遍。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>

using namespace std;
#define MAXN 100005
#define MAXM 505
#define INF 0x7fffffff
#define ll long long

int hd[MAXN],to[MAXN<<1],nxt[MAXN<<1],cnt;
int A[MAXN],p[MAXN],num;
bool isp[MAXN],vis[MAXN];
int dp[MAXN];vector<int> v[MAXN];
inline int read(){
    int x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

inline void addedge(int u,int v){
    to[++cnt]=v,nxt[cnt]=hd[u];
    hd[u]=cnt;return;
}

inline void init(){
    for(int i=2;i<=MAXN;i++){
        if(!isp[i]) isp[i]=1,p[++num]=i;
        for(int j=1;j<=num && p[j]*i<=MAXN;j++)
            {isp[p[j]*i]=1;if(i%p[j]==0) break;}
    }return;    
}

inline int dfs(int u,int fa,int x){
    int maxans=0,mx=0,cx=0;
    for(int i=hd[u];i;i=nxt[i]){
        int v=to[i];
        if(v==fa) continue;
        if(A[v]%x==0){
            maxans=max(maxans,dfs(v,u,x));
            if(dp[v]>mx) cx=mx,mx=dp[v];
            else if(dp[v]>cx) cx=dp[v];
        }
    }
    dp[u]=1+mx;return max(maxans,1+mx+cx);
}

int main(){
    //freopen("gtree3.in","r",stdin);
    //freopen("mine.out","w",stdout);
    int N=read(),ans=0;init();
    for(int i=1;i<=N-1;i++){
        int u=read(),v=read();
        addedge(u,v);addedge(v,u);
    }
    for(int i=1;i<=N;i++){
        A[i]=read();int x=A[i];
        for(int j=1;(j<=num)&&(p[j]*p[j]<=A[i]);j++){
            if(x%p[j]==0) v[i].push_back(p[j]); 
            while(x%p[j]==0) x/=p[j];
            if(x==1) break;
        }
        if(x>1) v[i].push_back(x);
    }
    for(int i=1;i<=N;i++)
        for(int j=0;j<v[i].size();j++)
            if(!vis[v[i][j]])
                ans=max(ans,dfs(i,0,v[i][j])),vis[v[i][j]]=1;
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/YSFAC/p/9747694.html