zoukankan      html  css  js  c++  java
  • 校内集训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;
    }
  • 相关阅读:
    怎样装两个MySQL服务器
    MySQL 8.0.12的安装与卸载
    位运算符2
    位运算符
    赋值运算符
    love心形
    变量之间运算
    变量
    标识符
    算术运算符
  • 原文地址:https://www.cnblogs.com/YSFAC/p/9747694.html
Copyright © 2011-2022 走看看